LeetCode 阿里天池专场 03. 整理书架
原地址:https://leetcode.cn/contest/tianchi2022/problems/ev2bru/
书架上有若干本书,从左至右的书籍编号记于整型数组 order
中。为保证书籍多样性,管理员想取走一些重复编号的书籍,要求满足以下条件:
剩余书本中相同编号的书本数量均不大于 limit
- 取走的书籍数量尽可能少
- 由于存在多种整理方案,请返回剩余书本编号的排列为「最小排列」的方案。
注意:
- 「最小排列」:若干数组中第一位数字最小的数组;若第一位数字相同,则为第二位数字最小的数组,以此类推。
Solution(贪心&单调栈)
题解参考:https://www.bilibili.com/video/BV1ne4y177wN
- 字典序最小
==>
贪心 - 依次遍历数组,应该装入更小的,弹出更大的
==>
单调栈
- 首先记录每本书的数量;
- 依次遍历书列表:
- 若当前书已经入栈的数量等于 limit,则不需要再入栈,并将该书剩余数量 - 1,进行下一次遍历
- 否则,循环判断,若当前书序号小于栈顶书的序号
&&
栈顶书的剩余数量大于 limit,将栈顶书弹出,并将栈顶书已经入栈的数量 - 1,剩余栈顶书序号数量 - 1 - 最后将当前书入栈,并将当前书已经入栈的数量 + 1
注意代码中的一个点:
left
记录全部的(包括栈内和还没遍历到)每种书的数量counter
只记录已经入栈的每种书的数量
public int[] arrangeBookshelf(int[] order, int limit) {
// 每本书剩余数量
Map<Integer, Integer> left = new HashMap<>();
for (int x : order) {
left.put(x, left.getOrDefault(x, 0) + 1);
}
Deque<Integer> stack = new LinkedList<>();
// 插入一个 0 作比较
stack.push(0);
// 已经加入栈中的元素计数
Map<Integer, Integer> counter = new HashMap<>();
for (int x : order) {
// 遍历的同时需要保证栈里面的元素出现次数不超过 limit
if (counter.getOrDefault(x, 0) == limit) {
left.put(x, left.get(x) - 1);
continue;
}
// 只有当前书序号比栈顶书序号小,并且栈顶书剩余数量必须大于 limit
while (x < stack.peek() && left.get(stack.peek()) > limit) {
Integer top = stack.poll();
left.put(top, left.get(top) - 1);
counter.put(top, counter.getOrDefault(top, 0) - 1);
}
stack.push(x);
counter.put(x, counter.getOrDefault(x, 0) + 1);
}
// 弹出 0
stack.pollLast();
// 存入数组
int[] ans = new int[stack.size()];
int k = ans.length;
while(!stack.isEmpty()) {
ans[--k] = stack.poll();
}
return ans;
}