牛客刷题——单调栈

题目:给定一个可能含有重复值的数组 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;
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值