O(logn) for both seat and leave. Easy and well commented solution with approach.
The idea is that whenever we seat a student, the student divides the interval between the next available left and right students into two parts. \n2. Have a Pri
1. The idea is that whenever we seat a student, the student divides the interval between the next available left and right students into two parts. \n2. Have a PriorityQueue(TreeSet here) that gives you the largest interval where a new student can sit at any point\n3. Whenever a student leaves merge the left and right interval and add it back to the queue.\n\n```\n    // Interval class to give the length and mid point of the interval\n    class Interval implements Comparable<Interval> {\n        int start;\n        int end;\n        Interval(int start, int end) {\n            this.start = start;\n            this.end = end;\n        }\n        \n        // gives the mid point of the interval\n        int mid() {\n            return (start + end)/2;\n        }\n        \n        // gives the interval length. handles cases for first and last element\n        // if first or last seat and it is empty then return the closest student. else return the closest student on either side\n        int diff() {\n            if (this.start == 0 && !set.contains(0)) {\n                return this.end;\n            }\n            if (this.end == n-1 && !set.contains(n-1)) {\n                return n-1 - this.start;\n            }\n            return (this.end-this.start)/2;\n        }\n        \n        // sort by length first. If they are the same, then sort by start index\n        public int compareTo(Interval a) {\n            if (this.diff() == a.diff()) {\n                return Integer.compare(a.start, this.start);\n            } else {\n                return Integer.compare(this.diff(), a.diff());\n            }\n        }\n    }\n    \n    TreeSet<Interval> q;\n    \n    TreeSet<Integer> set;\n    \n    int n;\n    \n    public ExamRoom(int n) {\n        set = new TreeSet<>();\n        q = new TreeSet<>();\n        q.add(new Interval(0, n-1));\n        this.n = n;\n    }\n    \n    public int seat() {\n        // get intervals by highest length\n        Interval in = q.pollLast();\n        // cases for ends of the array\n        if (in.start == 0) {\n            if (!set.contains(0)) {\n                set.add(0);\n                q.add(new Interval(in.start, in.end));\n                return 0;\n            }\n        }\n        if (in.end == this.n-1) {\n            if (!set.contains(n-1)) {\n                set.add(n-1);\n                q.add(new Interval(in.start, in.end));\n                return n-1;\n            }\n        }\n        int mid = in.mid();\n        set.add(mid);\n        \n        // get the left interval and right interval\n        Interval left = new Interval(in.start, mid);\n        Interval right = new Interval(mid, in.end);\n        // if the interval has more empty seats, add it\n        if (left.diff() > 0) {\n            q.add(left);\n        }\n        if (right.diff() > 0) {\n            q.add(right);\n        }\n        return mid;\n    }\n    \n    public void leave(int p) {\n        // get the next and previous closest student\n        Integer lower = set.lower(p);\n        Integer higher = set.higher(p);\n        \n        // cases for ends of array\n        if (higher != null) {\n            q.remove(new Interval(p, higher));\n        }\n        if (lower != null) {\n            q.remove(new Interval(lower, p));\n        }\n\n        set.remove(p);\n        \n        //merge the left and right intervals\n        if (lower == null && higher == null) {\n            q.add(new Interval(0, n-1));\n        } else if (lower == null) {\n            q.add(new Interval(0, higher));\n        } else if (higher == null) {\n            q.add(new Interval(lower, n-1));\n        } else {\n            q.add(new Interval(lower, higher));  \n        }\n        \n    }\n\n```
[]