[LeetCode] 855. Exam Room 考場


In an exam room, there are N seats in a single row, numbered 0, 1, 2, ..., N-1.

When a student enters the room, they must sit in the seat that maximizes the distance to the closest person.  If there are multiple such seats, they sit in the seat with the lowest number.  (Also, if no one is in the room, then the student sits at seat number 0.)

Return a class ExamRoom(int N) that exposes two functions: ExamRoom.seat() returning an int representing what seat the student sat in, and ExamRoom.leave(int p) representing that the student in seat number p now leaves the room.  It is guaranteed that any calls to ExamRoom.leave(p) have a student sitting in seat p.

Example 1:

Input: ["ExamRoom","seat","seat","seat","seat","leave","seat"], [[10],[],[],[],[],[4],[]] Output: [null,0,9,4,2,null,5] Explanation: ExamRoom(10) -> null seat() -> 0, no one is in the room, then the student sits at seat number 0. seat() -> 9, the student sits at the last seat number 9. seat() -> 4, the student sits at the last seat number 4. seat() -> 2, the student sits at the last seat number 2. leave(4) -> null seat() -> 5, the student sits at the last seat number 5.​​​​​​​

Note:

  1. 1 <= N <= 10^9
  2. ExamRoom.seat() and ExamRoom.leave() will be called at most 10^4 times across all test cases.
  3. Calls to ExamRoom.leave(p) are guaranteed to have a student currently sitting in seat number p.

在一個考場中,有N個座位在一排,當學生進入房間時,他們必須坐在與最近的人距離最大的座位上。 如果有多個這樣的座位,他們就坐在座位編號最小的座位上。(另外,如果沒有人在房間里,那么學生就坐在0號座位上。)實現一個類ExamRoom(int N),含有2個函數,ExamRoom.seat()返回學生應該坐的位置和ExamRoom.leave(int p)返回離開座位的學生。

解法1:最大堆, T: seat: O(logn), leave O(n),S: O(n)。用一個max heap來記錄所有兩個相鄰位置的間距,每次進來一個學生就pop出堆頂的位置,然后分配中間位子給學生,同時用一個數組記錄當前位子的學生,再把新形成的兩個相鄰位置push到heap。當學生離開時,從數組中找到相應位置的學生,從數組中去除,同時去除heap中由這個位置形成的兩個間距距離。

解法2: Use a list L to record the index of seats where people sit. T: O(N) for seat() and leave()

seat():
1. find the biggest distance at the start, at the end and in the middle.
2. insert index of seat
3. return index

leave(p): pop out p

Java:

    int N;
    ArrayList<Integer> L = new ArrayList<>();
    public ExamRoom(int n) {
        N = n;
    }

    public int seat() {
        if (L.size() == 0) {
            L.add(0);
            return 0;
        }
        int d = Math.max(L.get(0), N - 1 - L.get(L.size() - 1));
        for (int i = 0; i < L.size() - 1; ++i) d = Math.max(d, (L.get(i + 1) - L.get(i)) / 2);
        if (L.get(0) == d) {
            L.add(0, 0);
            return 0;
        }
        for (int i = 0; i < L.size() - 1; ++i)
            if ((L.get(i + 1) - L.get(i)) / 2 == d) {
                L.add(i + 1, (L.get(i + 1) + L.get(i)) / 2);
                return L.get(i + 1);
            }
        L.add(N - 1);
        return N - 1;
    }

    public void leave(int p) {
        for (int i = 0; i < L.size(); ++i) if (L.get(i) == p) L.remove(i);
    }  

Java:

// PriorityQueue
class ExamRoom {
    PriorityQueue<Interval> pq;
    int N;

    class Interval {
        int x, y, dist;
        public Interval(int x, int y) {
            this.x = x;
            this.y = y;
            if (x == -1) {
                this.dist = y;
            } else if (y == N) {
                this.dist = N - 1 - x;
            } else {
                this.dist = Math.abs(x - y) / 2;    
            }
        }
    }

    public ExamRoom(int N) {
        this.pq = new PriorityQueue<>((a, b) -> a.dist != b.dist? b.dist - a.dist : a.x - b.x);
        this.N = N;
        pq.add(new Interval(-1, N));
    }

    // O(logn): poll top candidate, split into two new intervals
    public int seat() {
        int seat = 0;
        Interval interval = pq.poll();
        if (interval.x == -1) seat = 0;
        else if (interval.y == N) seat = N - 1;
        else seat = (interval.x + interval.y) / 2; 
        
        pq.offer(new Interval(interval.x, seat));
        pq.offer(new Interval(seat, interval.y));
            
        return seat;
    }
    
    // O(n)Find head and tail based on p. Delete and merge two ends
    public void leave(int p) {
        Interval head = null, tail = null;
        List<Interval> intervals = new ArrayList<>(pq);
        for (Interval interval : intervals) {
            if (interval.x == p) tail = interval;
            if (interval.y == p) head = interval;
            if (head != null && tail != null) break;
        }
        // Delete
        pq.remove(head);
        pq.remove(tail);
        // Merge
        pq.offer(new Interval(head.x, tail.y));
    }
}

Python:

# Time:  seat:  O(logn) on average,
#        leave: O(logn)
# Space: O(n)

import heapq

LEN, POS, L, R = range(4)
LEFT, RIGHT = range(2)


class ExamRoom(object):

    def __init__(self, N):
        """
        :type N: int
        """
        self.__num = N
        self.__max_heap = [(-self.__num, 0, -1, self.__num)]
        self.__seats = {-1: [-1, self.__num],
                        self.__num: [-1, self.__num]}

    def seat(self):
        """
        :rtype: int
        """
        while self.__max_heap[0][L] not in self.__seats or \
                self.__max_heap[0][R] not in self.__seats or \
                self.__seats[self.__max_heap[0][L]][RIGHT] != \
                self.__max_heap[0][R] or \
                self.__seats[self.__max_heap[0][R]][LEFT] != \
                self.__max_heap[0][L]:
            heapq.heappop(self.__max_heap)  # lazy deletion

        curr = heapq.heappop(self.__max_heap)
        if curr[L] == -1 and curr[R] == self.__num:
            heapq.heappush(self.__max_heap, (-(curr[R]-1),
                                             curr[R]-1,
                                             curr[L]+1, curr[R]))
        elif curr[L] == -1:
            heapq.heappush(self.__max_heap, (-(curr[R]//2),
                                             curr[R]//2,
                                             curr[L]+1, curr[R]))
        elif curr[R] == self.__num:
            heapq.heappush(self.__max_heap, (-((curr[R]-1-curr[L])//2),
                                             (curr[R]-1-curr[L])//2+curr[L],
                                             curr[L], curr[R]-1))
        else:
            heapq.heappush(self.__max_heap, (-((curr[POS]-curr[L])//2),
                                             (curr[POS]-curr[L])//2+curr[L],
                                             curr[L], curr[POS]))
            heapq.heappush(self.__max_heap, (-((curr[R]-curr[POS])//2),
                                             (curr[R]-curr[POS])//2+curr[POS],
                                             curr[POS], curr[R]))
        self.__seats[curr[POS]] = [curr[L], curr[R]]
        self.__seats[curr[L]][RIGHT] = curr[POS]
        self.__seats[curr[R]][LEFT] = curr[POS]
        return curr[POS]

    def leave(self, p):
        """
        :type p: int
        :rtype: void
        """
        neighbors = self.__seats[p]
        self.__seats.pop(p)
        if neighbors[LEFT] == -1 and neighbors[RIGHT] == self.__num:
            heapq.heappush(self.__max_heap,
                           (-neighbors[RIGHT],
                            neighbors[LEFT]+1,
                            neighbors[LEFT], neighbors[RIGHT]))
        elif neighbors[LEFT] == -1:
            heapq.heappush(self.__max_heap,
                           (-neighbors[RIGHT],
                            neighbors[LEFT]+1,
                            neighbors[LEFT], neighbors[RIGHT]))
        elif neighbors[RIGHT] == self.__num:
            heapq.heappush(self.__max_heap,
                           (-(neighbors[RIGHT]-1-neighbors[LEFT]),
                            neighbors[RIGHT]-1,
                            neighbors[LEFT], neighbors[RIGHT]))
        else:
            heapq.heappush(self.__max_heap,
                           (-((neighbors[RIGHT]-neighbors[LEFT])//2),
                            (neighbors[RIGHT]-neighbors[LEFT])//2 +
                            neighbors[LEFT],
                            neighbors[LEFT], neighbors[RIGHT]))
        self.__seats[neighbors[LEFT]][RIGHT] = neighbors[RIGHT]
        self.__seats[neighbors[RIGHT]][LEFT] = neighbors[LEFT]  

Python:

def __init__(self, N):
        self.N, self.L = N, []

    def seat(self):
        N, L = self.N, self.L
        if not L: res = 0
        else:
            d, res = L[0], 0
            for a, b in zip(L, L[1:]):
                if (b - a) / 2 > d:
                    d, res = (b - a) / 2, (b + a) / 2
            if N - 1 - L[-1] > d: res = N - 1
        bisect.insort(L, res)
        return res

    def leave(self, p):
        self.L.remove(p)  

Python: O(log n) time for both seat() and leave() with heapq and dicts

from heapq import heappop, heappush


class ExamRoom(object):

    def __init__(self, N):
        """
        :type N: int
        """
        self.N = N
        self.heap = []
        self.avail_first = {}
        self.avail_last = {}
        self.put_segment(0, self.N - 1)

    def put_segment(self, first, last):

        if first == 0 or last == self.N - 1:
            priority = last - first
        else:
            priority = (last - first) // 2

        segment = [-priority, first, last, True]

        self.avail_first[first] = segment
        self.avail_last[last] = segment

        heappush(self.heap, segment)

    def seat(self):
        """
        :rtype: int
        """
        while True:
            _, first, last, is_valid = heappop(self.heap)

            if is_valid:
                del self.avail_first[first]
                del self.avail_last[last]
                break

        if first == 0:
            ret = 0
            if first != last:
                self.put_segment(first + 1, last)

        elif last == self.N - 1:
            ret = last
            if first != last:
                self.put_segment(first, last - 1)

        else:
            ret = first + (last - first) // 2

            if ret > first:
                self.put_segment(first, ret - 1)

            if ret < last:
                self.put_segment(ret + 1, last)

        return ret

    def leave(self, p):
        """
        :type p: int
        :rtype: void
        """
        first = p
        last = p

        left = p - 1
        right = p + 1

        if left >= 0 and left in self.avail_last:
            segment_left = self.avail_last.pop(left)
            segment_left[3] = False
            first = segment_left[1]

        if right < self.N and right in self.avail_first:
            segment_right = self.avail_first.pop(right)
            segment_right[3] = False
            last = segment_right[2]

        self.put_segment(first, last)

C++:

 int N;
    vector<int> L;
    ExamRoom(int n) {
        N = n;
    }

    int seat() {
        if (L.size() == 0) {
            L.push_back(0);
            return 0;
        }
        int d = max(L[0], N - 1 - L[L.size() - 1]);
        for (int i = 0; i < L.size() - 1; ++i) d = max(d, (L[i + 1] - L[i]) / 2);
        if (L[0] == d) {
            L.insert(L.begin(), 0);
            return 0;
        }
        for (int i = 0; i < L.size() - 1; ++i)
            if ((L[i + 1] - L[i]) / 2 == d) {
                L.insert(L.begin() + i + 1, (L[i + 1] + L[i]) / 2);
                return L[i + 1];
            }
        L.push_back(N - 1);
        return N - 1;
    }

    void leave(int p) {
        for (int i = 0; i < L.size(); ++i) if (L[i] == p) L.erase(L.begin() + i);
    }

C++:  

// Time:  seat:  O(logn),
//        leave: O(logn)
// Space: O(n)

class ExamRoom {
public:
    ExamRoom(int N) : num_(N) {
        segment_iters_[make_pair(-1, num_)] = 
            max_bst_.emplace(make_shared<Segment>(num_, 0, -1, num_));
        seats_[-1] = make_pair(-1, num_);
        seats_[num_] = make_pair(-1, num_);
    }
    
    int seat() {
        const auto curr = *max_bst_.begin(); max_bst_.erase(max_bst_.begin());
        segment_iters_.erase(make_pair(curr->l, curr->r));
        if (curr->l == -1 && curr->r == num_) {
            segment_iters_[make_pair(curr->l + 1, curr->r)] = max_bst_.emplace(
                make_shared<Segment>(curr->r - 1,
                                     curr->r - 1,
                                     curr->l + 1, curr->r));
        } else if (curr->l == -1) {
            segment_iters_[make_pair(curr->l + 1, curr->r)] = max_bst_.emplace(
                make_shared<Segment>(curr->r / 2,
                                     curr->r / 2,
                                     curr->l + 1, curr->r));
        } else if (curr->r == num_) {
            segment_iters_[make_pair(curr->l, curr->r - 1)] = max_bst_.emplace(
                make_shared<Segment>((curr->r - 1 - curr->l) / 2,
                                     (curr->r - 1 - curr->l) / 2 + curr->l,
                                     curr->l, curr->r - 1)); 
        } else {
            segment_iters_[make_pair(curr->l, curr->pos)] = max_bst_.emplace(
                make_shared<Segment>((curr->pos - curr->l) / 2,
                                     (curr->pos - curr->l) / 2 + curr->l,
                                     curr->l, curr->pos));
            segment_iters_[make_pair(curr->pos, curr->r)] = max_bst_.emplace(
                make_shared<Segment>((curr->r - curr->pos) / 2,
                                     (curr->r - curr->pos) / 2 + curr->pos,
                                     curr->pos, curr->r));
        }
        seats_[curr->pos] = make_pair(curr->l, curr->r);
        seats_[curr->l].second = curr->pos;
        seats_[curr->r].first = curr->pos;
        return curr->pos;
    }
    
    void leave(int p) {
        const auto neighbors = seats_[p];
        seats_.erase(p);
        const auto& left_segment = make_pair(neighbors.first, p);
        if (segment_iters_.count(left_segment)) {
            max_bst_.erase(segment_iters_[left_segment]); segment_iters_.erase(left_segment);
        }
        const auto& right_segment = make_pair(p, neighbors.second);
        if (segment_iters_.count(right_segment)) {
            max_bst_.erase(segment_iters_[right_segment]); segment_iters_.erase(right_segment);
        }
        
        if (neighbors.first == -1 && neighbors.second == num_) {
            segment_iters_[neighbors] = max_bst_.emplace(
                make_shared<Segment>(neighbors.second,
                                     neighbors.first + 1, 
                                     neighbors.first, neighbors.second));
        } else if (neighbors.first == -1) {
            segment_iters_[neighbors] = max_bst_.emplace(
                make_shared<Segment>(neighbors.second,
                                     neighbors.first + 1,
                                     neighbors.first, neighbors.second));
        } else if (neighbors.second == num_) {
            segment_iters_[neighbors] = max_bst_.emplace(
                make_shared<Segment>(neighbors.second - 1 - neighbors.first,
                                     neighbors.second - 1, 
                                     neighbors.first, neighbors.second));
        } else {
            segment_iters_[neighbors] = max_bst_.emplace(
                make_shared<Segment>((neighbors.second - neighbors.first) / 2,
                                     (neighbors.second - neighbors.first) / 2 + neighbors.first,
                                     neighbors.first, neighbors.second));
        }
        seats_[neighbors.first].second = neighbors.second;
        seats_[neighbors.second].first = neighbors.first;
    }
    
private:
    struct Segment {
        int dis;
        int pos;
        int l;
        int r;
        Segment(int dis, int pos, int l, int r) : 
            dis(dis), pos(pos), l(l), r(r) {
        }
    };
    
    template <typename T>
    struct Compare {
        bool operator()(const T& a, const T& b) {
            return a->dis == b->dis ?
                less<int>()(a->l, b->l) :
                greater<int>()(a->dis, b->dis);
        }
    };
    
    template <typename T>
    struct PairHash {
        size_t operator()(const pair<T, T>& p) const {
            size_t seed = 0;
            seed ^= std::hash<T>{}(p.first)  + 0x9e3779b9 + (seed<<6) + (seed>>2);
            seed ^= std::hash<T>{}(p.second) + 0x9e3779b9 + (seed<<6) + (seed>>2);
            return seed;
        }
    };
    
    int num_;
    using S = shared_ptr<Segment>;
    multiset<S, Compare<S>> max_bst_;
    unordered_map<int, pair<int, int>> seats_;
    unordered_map<pair<int, int>, multiset<S, Compare<S>>::iterator, PairHash<int>> segment_iters_;
};

// Time:  seat:  O(logn) on average,
//        leave: O(logn)
// Space: O(n)
class ExamRoom2 {
public:
    ExamRoom2(int N) : num_(N) {
        max_bst_.emplace(make_shared<Segment>(num_, 0, -1, num_));
        seats_[-1] = make_pair(-1, num_);
        seats_[num_] = make_pair(-1, num_);
    }
    
    int seat() {
        while (!seats_.count((*max_bst_.cbegin())->l) ||
               !seats_.count((*max_bst_.cbegin())->r) ||
               seats_[(*max_bst_.cbegin())->l].second != (*max_bst_.cbegin())->r ||
               seats_[(*max_bst_.cbegin())->r].first != (*max_bst_.cbegin())->l) {
            max_bst_.erase(max_bst_.begin());  // lazy deletion
        }
        
        const auto curr = *max_bst_.begin(); max_bst_.erase(max_bst_.begin());
        if (curr->l == -1 && curr->r == num_) {
            max_bst_.emplace(
                make_shared<Segment>(curr->r - 1,
                                     curr->r - 1,
                                     curr->l + 1, curr->r));
        } else if (curr->l == -1) {
            max_bst_.emplace(
                make_shared<Segment>(curr->r / 2,
                                     curr->r / 2,
                                     curr->l + 1, curr->r));
        } else if (curr->r == num_) {
            max_bst_.emplace(
                make_shared<Segment>((curr->r - 1 - curr->l) / 2,
                                     (curr->r - 1 - curr->l) / 2 + curr->l,
                                     curr->l, curr->r - 1)); 
        } else {
            max_bst_.emplace(
                make_shared<Segment>((curr->pos - curr->l) / 2,
                                     (curr->pos - curr->l) / 2 + curr->l,
                                     curr->l, curr->pos));
            max_bst_.emplace(
                make_shared<Segment>((curr->r - curr->pos) / 2,
                                     (curr->r - curr->pos) / 2 + curr->pos,
                                     curr->pos, curr->r));
        }
        seats_[curr->pos] = make_pair(curr->l, curr->r);
        seats_[curr->l].second = curr->pos;
        seats_[curr->r].first = curr->pos;
        return curr->pos;
    }
    
    void leave(int p) {
        const auto neighbors = seats_[p];
        seats_.erase(p);
        if (neighbors.first == -1 && neighbors.second == num_) {
            max_bst_.emplace(
                make_shared<Segment>(neighbors.second,
                                     neighbors.first + 1,
                                     neighbors.first, neighbors.second));
        } else if (neighbors.first == -1) {
            max_bst_.emplace(
                make_shared<Segment>(neighbors.second,
                                     neighbors.first + 1,
                                     neighbors.first, neighbors.second));
        } else if (neighbors.second == num_) {
            max_bst_.emplace(
                make_shared<Segment>(neighbors.second - 1 - neighbors.first,
                                     neighbors.second - 1,
                                     neighbors.first, neighbors.second));
        } else {
            max_bst_.emplace(
                make_shared<Segment>((neighbors.second - neighbors.first) / 2,
                                     (neighbors.second - neighbors.first) / 2 + neighbors.first,
                                     neighbors.first, neighbors.second));
        }
        seats_[neighbors.first].second = neighbors.second;
        seats_[neighbors.second].first = neighbors.first;
    }
    
private:
    struct Segment {
        int dis;
        int pos;
        int l;
        int r;
        Segment(int dis, int pos, int l, int r) : 
            dis(dis), pos(pos), l(l), r(r) {
        }
    };
    
    template <typename T>
    struct Compare {
        bool operator()(const T& a, const T& b) {
            return a->dis == b->dis ?
                less<int>()(a->l, b->l) :
                greater<int>()(a->dis, b->dis);
        }
    };
    
    int num_;
    using S = shared_ptr<Segment>;
    multiset<S, Compare<S>> max_bst_;
    unordered_map<int, pair<int, int>> seats_;
};

// Time:  seat:  O(logn) on average,
//        leave: O(logn)
// Space: O(n)
class ExamRoom3 {
public:
    ExamRoom3(int N) : num_(N) {
        max_heap_.emplace(make_shared<Segment>(num_, 0, -1, num_));
        seats_[-1] = make_pair(-1, num_);
        seats_[num_] = make_pair(-1, num_);
    }
    
    int seat() {
        while (!seats_.count(max_heap_.top()->l) ||
               !seats_.count(max_heap_.top()->r) ||
               seats_[max_heap_.top()->l].second != max_heap_.top()->r ||
               seats_[max_heap_.top()->r].first != max_heap_.top()->l) {
            max_heap_.pop();  // lazy deletion
        }
        
        const auto curr = max_heap_.top(); max_heap_.pop();
        if (curr->l == -1 && curr->r == num_) {
            max_heap_.emplace(
                make_shared<Segment>(curr->r - 1,
                                     curr->r - 1,
                                     curr->l + 1, curr->r));
        } else if (curr->l == -1) {
            max_heap_.emplace(
                make_shared<Segment>(curr->r / 2,
                                     curr->r / 2,
                                     curr->l + 1, curr->r));
        } else if (curr->r == num_) {
            max_heap_.emplace(
                make_shared<Segment>((curr->r - 1 - curr->l) / 2,
                                     (curr->r - 1 - curr->l) / 2 + curr->l,
                                     curr->l, curr->r - 1)); 
        } else {
            max_heap_.emplace(
                make_shared<Segment>((curr->pos - curr->l) / 2,
                                     (curr->pos - curr->l) / 2 + curr->l,
                                     curr->l, curr->pos));
            max_heap_.emplace(
                make_shared<Segment>((curr->r - curr->pos) / 2,
                                     (curr->r - curr->pos) / 2 + curr->pos,
                                     curr->pos, curr->r));
        }
        seats_[curr->pos] = make_pair(curr->l, curr->r);
        seats_[curr->l].second = curr->pos;
        seats_[curr->r].first = curr->pos;
        return curr->pos;
    }
    
    void leave(int p) {
        const auto neighbors = seats_[p];
        seats_.erase(p);
        if (neighbors.first == -1 && neighbors.second == num_) {
            max_heap_.emplace(
                make_shared<Segment>(neighbors.second,
                                     neighbors.first + 1,
                                     neighbors.first, neighbors.second));
        } else if (neighbors.first == -1) {
            max_heap_.emplace(
                make_shared<Segment>(neighbors.second,
                                     neighbors.first + 1,
                                     neighbors.first, neighbors.second));
        } else if (neighbors.second == num_) {
            max_heap_.emplace(
                make_shared<Segment>(neighbors.second - 1 - neighbors.first,
                                     neighbors.second - 1,
                                     neighbors.first, neighbors.second));
        } else {
            max_heap_.emplace(
                make_shared<Segment>((neighbors.second - neighbors.first) / 2,
                                     (neighbors.second - neighbors.first) / 2 + neighbors.first,
                                     neighbors.first, neighbors.second));
        }
        seats_[neighbors.first].second = neighbors.second;
        seats_[neighbors.second].first = neighbors.first;
    }
    
private:
    struct Segment {
        int dis;
        int pos;
        int l;
        int r;
        Segment(int dis, int pos, int l, int r) : 
            dis(dis), pos(pos), l(l), r(r) {
        }
    };
    
    template <typename T>
    struct Compare {
        bool operator()(const T& a, const T& b) {
            return a->dis == b->dis ?
                greater<int>()(a->l, b->l) :
                less<int>()(a->dis, b->dis);
        }
    };
    
    int num_;
    using S = shared_ptr<Segment>;
    priority_queue<S, vector<S>, Compare<S>> max_heap_;
    unordered_map<int, pair<int, int>> seats_;
};

/**
 * Your ExamRoom object will be instantiated and called as such:
 * ExamRoom obj = new ExamRoom(N);
 * int param_1 = obj.seat();
 * obj.leave(p);
 */

  

 

All LeetCode Questions List 題目匯總


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM