leetcode
leetcode 1101 ~ 1150
餐盘栈

餐盘栈

难度:

标签:

题目描述

代码结果

运行时间: 438 ms, 内存: 91.9 MB


/* 
 * 思路:
 * 1. 使用List和Optional处理栈的数据结构。
 * 2. push方法将元素推入第一个非满栈,或创建新栈。
 * 3. pop方法返回第一个非空栈的栈顶元素。
 * 4. popAtStack方法从指定栈中返回栈顶元素。
 */
import java.util.*;
import java.util.stream.*;

class DinnerPlates {
    private List<Stack<Integer>> stacks;
    private int capacity;
    private PriorityQueue<Integer> available;

    public DinnerPlates(int capacity) {
        this.capacity = capacity;
        this.stacks = new ArrayList<>();
        this.available = new PriorityQueue<>();
    }

    public void push(int val) {
        if (!available.isEmpty() && available.peek() < stacks.size()) {
            int index = available.poll();
            stacks.get(index).push(val);
            if (stacks.get(index).size() == capacity) {
                available.remove(index);
            }
        } else {
            Stack<Integer> stack = new Stack<>();
            stack.push(val);
            stacks.add(stack);
            if (capacity > 1) available.add(stacks.size() - 1);
        }
    }

    public int pop() {
        return IntStream.rangeClosed(1, stacks.size())
            .mapToObj(i -> stacks.get(stacks.size() - i))
            .filter(s -> !s.isEmpty())
            .findFirst()
            .map(s -> {
                int val = s.pop();
                if (s.size() == capacity - 1) available.add(stacks.size() - 1);
                return val;
            })
            .orElse(-1);
    }

    public int popAtStack(int index) {
        if (index >= stacks.size() || stacks.get(index).isEmpty()) return -1;
        int val = stacks.get(index).pop();
        if (stacks.get(index).size() == capacity - 1) available.add(index);
        return val;
    }
}

解释

方法:

该题解使用了多个栈和一个有序集合来实现餐盘类。主要思路如下: 1. 用一个列表 `stack` 来存储所有的餐盘,每个餐盘用一个整数表示。 2. 用一个列表 `top` 来存储每个栈的栈顶位置。 3. 用一个有序集合 `poppedPos` 来存储被弹出的位置。 4. 对于 `push` 操作,如果有被弹出的位置,就将新餐盘放到最左边的被弹出位置;否则,将新餐盘放到最右边的栈上。 5. 对于 `pop` 操作,从最右边的栈开始弹出餐盘,并更新 `top` 和 `poppedPos`。 6. 对于 `popAtStack` 操作,根据给定的栈编号计算出餐盘在 `stack` 中的位置,将其弹出,并更新 `top` 和 `poppedPos`。

时间复杂度:

O(log n),其中 n 为调用 `push` 的次数。

空间复杂度:

O(n),其中 n 为调用 `push` 的次数。

代码细节讲解

🦆
在实现 `DinnerPlates` 类的 `push` 操作时,你如何确定被弹出的位置是否真的是空的,以便放置新的餐盘?
在 `DinnerPlates` 类的 `push` 操作中,我们使用了一个有序集合 `poppedPos` 来追踪所有被弹出的位置。这些位置代表了栈中那些已经被弹出但尚未被新餐盘占据的空位。当执行 `push` 操作时,首先检查 `poppedPos` 集合是否为空。如果不为空,这意味着有可用的空位,我们从 `poppedPos` 中取出最小的位置(使用 `pop(0)`,这是因为 `SortedSet` 保持元素有序),并将新的餐盘放置在此位置。这样就确保了被弹出的位置在被重新填充前确实是空的。
🦆
对于 `pop` 操作,如何处理在有序集合 `poppedPos` 中删除元素的逻辑,特别是当最右边的餐盘已被弹出时你的处理方式是什么?
在 `pop` 操作中,如果最右边的餐盘已经被弹出(即位置在 `poppedPos` 中),那么在弹出最右边的餐盘之前需要先从 `poppedPos` 中移除这些位置。这通过检查 `poppedPos` 的最后一个元素是否等于 `stack` 最后一个元素的索引来完成。如果是,我们从 `stack` 和 `poppedPos` 中同时移除这些元素。此外,如果弹出位置正好是一个栈的开始位置,还需要从 `top` 列表中移除相应的栈顶索引。这个过程确保了 `poppedPos` 中的索引总是有效的,并且 `stack` 中不会留下无效的空洞。
🦆
在 `popAtStack` 方法中,如果栈顶的餐盘已被弹出,但栈中仍有其他餐盘,此时如何确保返回正确的餐盘值?
在 `popAtStack` 方法中,我们通过计算指定栈的当前栈顶位置来弹出餐盘。这是通过 `top[index]` 来得知的。在弹出之后,`top[index]` 会减一,表示栈顶向下移动了一个位置。此外,我们使用 `poppedPos` 集合来记录被弹出的位置,确保在随后的操作中这些位置可以被正确管理。即便栈顶的餐盘已被弹出,通过正确维护 `top` 和 `poppedPos`,我们总是能确保返回正确的餐盘值,因为这些值仍然保存在 `stack` 中,只是它们的索引被记录在了 `poppedPos` 中。

相关问题