leetcode
leetcode 1701 ~ 1750
最小未被占据椅子的编号

最小未被占据椅子的编号

难度:

标签:

题目描述

代码结果

运行时间: 129 ms, 内存: 20.4 MB


/* Problem statement: 
There are n friends attending a party, each arriving and leaving at specific times. Each friend will occupy the smallest numbered unoccupied chair upon arrival. We need to determine the chair number occupied by the target friend.

Solution using Java Stream API:
1. Sort the friends by their arrival times using Stream.
2. Use a TreeSet to keep track of the available chairs.
3. Iterate over sorted events and manage chair allocation and deallocation.
*/

import java.util.*;
import java.util.stream.*;

public class PartyChairsStream {
    public int smallestChair(int[][] times, int targetFriend) {
        int n = times.length;

        // List of events (arrival or leaving)
        List<int[]> events = IntStream.range(0, n)
            .mapToObj(i -> new int[][]{{times[i][0], i, 1}, {times[i][1], i, -1}})
            .flatMap(Arrays::stream)
            .sorted((a, b) -> a[0] == b[0] ? a[2] - b[2] : a[0] - b[0])
            .collect(Collectors.toList());

        // TreeSet to manage available chairs
        TreeSet<Integer> availableChairs = IntStream.range(0, n).boxed().collect(Collectors.toCollection(TreeSet::new));
        Map<Integer, Integer> occupiedChairs = new HashMap<>();

        for (int[] event : events) {
            int time = event[0];
            int friend = event[1];
            int type = event[2];

            if (type == 1) { // arrival
                int chair = availableChairs.pollFirst();
                occupiedChairs.put(friend, chair);
                if (friend == targetFriend) {
                    return chair;
                }
            } else { // leaving
                int chair = occupiedChairs.remove(friend);
                availableChairs.add(chair);
            }
        }

        return -1; // should never reach here
    }
}

解释

方法:

首先,解题思路是将每个朋友的到达和离开时间转换为一个事件列表,并包含每个朋友的索引。对这个列表根据到达时间进行排序。使用一个最小堆来跟踪当前可用的椅子编号,另一个最小堆来维护离开时间和对应的椅子编号。遍历每个事件,如果有朋友离开(即当前时间大于等于堆顶的离开时间),则将对应的椅子编号放回可用椅子堆中。如果有朋友到达,则从可用椅子堆中取出最小的椅子编号,并记录该朋友使用的椅子。如果当前到达的朋友是目标朋友,直接返回其所使用的椅子编号。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
在处理离开事件时,如何确保在多个朋友同时离开时,椅子编号能正确地被回收并且保持最小编号优先的原则?
在题解中,我们使用了一个最小堆来维护离开时间和椅子编号的关系。每个元素是一个元组,包含离开时间、椅子编号和朋友的索引。最小堆的性质确保了堆顶元素总是拥有最小的离开时间。在处理事件时,我们会循环检查堆顶元素的离开时间是否小于或等于当前事件的到达时间。如果是,就将该椅子编号回收至另一个最小堆(可用椅子堆)。由于这个可用椅子堆也是最小堆,它保证了每次从中取出或插入元素都会维持椅子编号的最小序,即每次都可以分配最小的未被占用的椅子编号。因此,即使多个朋友同时离开,我们也能确保椅子编号正确回收,且按照最小编号优先原则进行再分配。
🦆
代码实现中,当目标朋友到达时直接返回其椅子编号。如果在目标朋友到达之前处理完所有事件会对结果有什么影响?
在这个题解中,处理事件的逻辑是基于朋友的到达时间顺序进行的。每个到达事件都在处理完之前所有必要的离开事件之后立即处理。这意味着,只要目标朋友到达时,我们已经处理了所有先前到达且必须在目标朋友之前离开的朋友的离开事件。因此,如果在目标朋友到达之前处理所有事件,实际上我们只处理到目标朋友到达之前的事件。一旦目标朋友到达并被分配了椅子,我们就返回这个椅子编号作为结果,而不需要关心后续的任何事件。这不会影响结果,因为目标朋友的椅子编号一旦确定,即使后续有更多事件发生,也不会影响已经分配给目标朋友的椅子编号。

相关问题