题目:给定一个可能含有重复值的数组 arr,找到每一个 i 位置左边和右边离 i 位置最近且值比 arr[i] 小的位置。返回所有位置相应的信息。位置信息包括:两个数字 L 和 R,如果不存在,则值为 -1,下标从 0 开始。
eg:输入:[3,4,1,5,6,2,7] 输出:[[-1,2],[0,2],[-1,-1],[2,5],[3,5],[2,-1],[5,-1]]
看完题目想的还是暴力,没有想出如何使用栈来解决。。。本着不辜负题目用意的想法,看了答案解析,还是有很多人直接用暴力,看了使用单调栈的分析,还是强啊
栈的用处其实就是往前遍历,同时维持一个单增元素的下标,这样在从左向右处理的过程中,就可以完成第一部分,找到左边的比自己小的元素下标,使用同样的方法对数组从右向左再处理一遍,就可以找到右边比自己小的元素下标。
根据题目的意思,第一个元素是没有左边小的,因此对应 res 的元素置为 -1,最后一个元素是没有右边小的,因此也将对应位置置为-1。
以从左向右处理为例:首先将第一个元素入栈,从下标 1 开始进行遍历,对于数组的每一个元素,首先查看栈顶元素,比较栈顶元素下标 top 对应的元素和当前元素的大小,如果 nums[top] < 当前元素,great,当前元素左边小的元素下标就是 top ,然后将当前元素下标入栈,反之,nums[top] > 当前元素的话,那就需要在栈中进行查找,不断 pop ,直到栈顶元素是小于当前元素的,如果最后栈为空了,那就说明没有比当前元素小的,那对应的当前元素左边小为 -1 ,然后将当前元素下标入栈,对数组的每个元素进行处理。
采用同样的方法从右向左对数组进行处理,以获得每个元素的右边小。
完整代码如下:
public int[][] foundMonotoneStack (int[] nums) {
// write code here
int[][] res = new int[nums.length][2];
Stack<Integer> index = new Stack<>();
res[0][0] = -1;
res[nums.length-1][1] = -1;
index.push(0); //初始化栈
//从左向右进行处理
for(int i=1;i<nums.length;i++) {
//判断当前元素和栈顶元素的大小关系
int top = index.peek();
if(nums[i]>nums[top]) { //top left最小是i
res[i][0]=top;
}else {
while(!index.isEmpty()) {
top = index.peek();
if(nums[i]>nums[top]) {
res[i][0] = top;
break;
}else { //弹出大于当前元素
index.pop();
}
}
if(index.isEmpty()) {
res[i][0] = -1;
}
}
index.push(i);
}
index.clear();
index.push(nums.length-1);
//从右向左进行处理
for(int i=nums.length-2;i>=0;i--) {
//判断当前元素和栈顶元素的大小关系
int top = index.peek();
if(nums[i]>nums[top]) { //top left最小是i
res[i][1]=top;
}else {
while(!index.isEmpty()) {
top = index.peek();
if(nums[i]>nums[top]) {
res[i][1] = top;
break;
}else { //弹出大于当前元素
index.pop();
}
}
if(index.isEmpty()) {
res[i][1] = -1;
}
}
index.push(i);
}
return res;
}