「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」。
一、单调栈是什么?
单调栈(MonotonousStack)一种特别设计的栈结构,为了解决如下的问题:
给定一个可能含有重复值的数组arr,i位置的数一定存在如下两个信息:
- arr[i]的左侧离i最近并且小于或者大于arr[i]的数在哪?
- arr[i]的右侧里i最近并且小于或者大于arr[i]的数在哪?
二、单调栈能做什么?
如果想得到arr中所有位置的两个信息,怎么能让得到信息的过程尽量快。那么到底怎么设计呢?
数组中没有重复的数的设计方案
栈
public static int[][] getNearLessNoRepeat(int[] arr) {
if (arr == null || arr.length == 0) {
return null;
}
int N = arr.length;
int[][] ans = new int[N][2];
// 只存位置!
Stack<Integer> stack = new Stack<>();
// 遍历到i位置的数arr[i]
for (int i = 0; i < N; i++) {
// 当前位置的数比栈顶位置的数小,没有机会往上摞,则弹出栈顶
while (!stack.isEmpty() && arr[stack.peek()] > arr[i]) {
int j = stack.pop();
int leftLessIndex = stack.isEmpty() ? -1 : stack.peek();
ans[j][0] = leftLessIndex;
ans[j][1] = i;
}
stack.push(i);
}
while (!stack.isEmpty()) {
int j = stack.pop();
int leftLessIndex = stack.isEmpty() ? -1 : stack.peek();
ans[j][0] = leftLessIndex;
ans[j][1] = -1;
}
return ans;
}
数组中存在重复的数的设计方案
栈 + 链表(相同值存在一起)
public static int[][] getNearLess(int[] arr) {
if (arr == null || arr.length == 0) {
return null;
}
int N = arr.length;
int[][] ans = new int[N][2];
Stack<List<Integer>> stack = new Stack<>();
for (int i = 0; i < N; i++) {
while (!stack.isEmpty() && arr[stack.peek().get(0)] > arr[i]) {
List<Integer> popIds = stack.pop();
int leftLessIndex = stack.isEmpty() ? -1 : stack.peek().get(stack.peek().size() - 1);
for (Integer popId : popIds) {
ans[popId][0] = leftLessIndex;
ans[popId][1] = i;
}
}
if (!stack.isEmpty() && arr[stack.peek().get(0)] == arr[i]) {
stack.peek().add(i);
} else {
List<Integer> list = new ArrayList<>();
list.add(i);
stack.push(list);
}
}
while (!stack.isEmpty()) {
List<Integer> popIds = stack.pop();
int leftLessIndex = stack.isEmpty() ? -1 : stack.peek().get(stack.peek().size() - 1);
for (Integer popId : popIds) {
ans[popId][0] = leftLessIndex;
ans[popId][1] = -1;
}
}
return ans;
}