题三:221021天池-03. 整理书架
思路:单调栈
因为要求最小序列,并且只是去掉数组中的一些元素,并且是往后遍历才知道当前元素需要保留与否。
统计所有的元素出现的数目,记为bookCountMap,在遍历order中,我们还需要记录那些选中的数字的个数,记为usedBookMap。
1. 首先,我们判断当前元素cur是否能够入栈,如果说当前元素在之前已经用过limit次了,也就是used(cur) >= limit,那么这个时候只能放弃当前元素,并更新bookCountMap。
2. 如果当前元素cur可以入栈,那么我们还需要判断一下是否还需要移除栈顶元素top,直到能够确保最小化序列。
具体来说:
栈顶代表着最近一个满足条件的元素,设栈顶元素为top,当前元素为cur,
如果当前cur > top && count(top) > limit,那么此时就可以移除掉栈顶元素top了。
解释:
因为当top的总数大于limit的时候,就说明当前这个top可以移除,也可以移除。但是我们要确保最小的序列,所以说,如果当前值cur要比top更小,那么自然可以将这些不满足条件的top都移除掉。
3. 如果当前元素cur可以入栈,且栈顶也满足条件,那么就将当前元素加入栈中。
4. 最后的结果就是栈里面保存的数据,拿出来放到数组里面就好了。
栈顶元素需要满足的条件:
栈顶元素是不可被移出的,主要有如下两种情况:
- top的总数要比limit小,这种情况下不能移出栈顶。
- 还有一种情况就是top总数来看可以被移出,但是因为top < cur,如果移出了top,那么加入cur之后,序列肯定没有之前小。
代码:
class Solution {
public int[] arrangeBookshelf(int[] order, int limit) {
Stack<Integer> stack = new Stack<>();
Map<Integer, Integer> bookCountMap = new HashMap();
Map<Integer, Integer> usedBookMap = new HashMap();
for (int book : order) {
bookCountMap.compute(book, (key, value) -> value == null ? 1 : value + 1);
}
// 栈顶top需要满足, top < cur || (top > cur && count(top) <= limit)
int top;
for (int cur : order) {
// 如果之前已经有的book编号数量 < limit,那么可以将当前书本加进来。
if (usedBookMap.get(cur) == null || usedBookMap.get(cur) < limit) {
while (!stack.empty() && (cur < (top = stack.peek()) && bookCountMap.get(top) > limit)) {
stack.pop();
bookCountMap.put(top, bookCountMap.get(top) - 1);
if (usedBookMap.get(top) != null && usedBookMap.get(top) > 0) {
usedBookMap.put(top, usedBookMap.get(top) - 1);
}
}
stack.push(cur);
usedBookMap.compute(cur, (key, value) -> value == null ? 1 : value + 1);
} else {
bookCountMap.put(cur, bookCountMap.get(cur) - 1);
}
}
int[] res = new int[stack.size()];
for (int i = res.length - 1; i > -1; i--) {
res[i] = stack.pop();
}
return res;
}
}