单吊顾名思义,就是听牌之后胡一张的打法。。。。拿错课本了不好意思
大部分的算法题你做不出来的原因,都是你没找到合适的方法,更简单的说就是你没见过更合适的方法,更关乎知识的广度,比如今天所说的单调栈
大部分算法只要你脑袋里面能流畅的想象出整个过程,写出代码debug一下,基本就能AC,单调栈的代码很简单,但是却不是那么好复现过程。
leetcode里面最典型的题就是利用单调栈解找下一个最大的问题,理解单调栈有点像你最开始理解dp数组一样,你得明白它含义是什么,搞清楚什么含义,会更快,上题目:
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
示例 1:
输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2
给大家用所谓单调栈还原一下整个过程,不过我们换个数组
输入nums[] = [1,1,0,2,1,4]
结果res[] = [-1...]因为找不到就是-1,初始化-1不用额外去填写
单调栈中存储的内容就是还没有找到下一个比自己大的元素的下标,将要入栈的是下一次要找比自己大元素的下标
操作上遍历数组开始即可,栈中为空,正常入栈
(1)栈:【】,index = 0,栈为空,正常入栈 ,此时 栈:【0】
(2)栈:【0】,index = 1,栈不为空,1是上一个没有找到比自己大的元素的下标,比较nums[0]和nums[1(index)],此时index=0元素还是没有找到比自己大的元素,不出栈,index=1元素入栈
此时 栈:【0,1】
(3)栈:【0,1】index = 2,1是上一个没有找到比自己大的元素的下标,比较nums[1]和nums[2],此时index=1元素还是没有找到比自己大的元素,不出栈,index=2元素入栈
(4)栈:【0,1,2】index = 3,2是上一个没有找到比自己大的元素的下标,比较nums[2]和nums[3],此时index=2元素找到比自己大的元素,那么index = 2 必须出栈,res[2(栈顶元素下标)] = nums[3(index)],此时 栈:【0,1】,由于nums[3]>nums[2]有可能也大于nums[1],那么继续比较栈顶元素nums[1]和当前元素nums[3(index)],由于nums[3]>nums[1],那么1也要出栈,并且res[1]=nums[3],同理,栈中0元素也出栈,栈为空。至此,之前所有元素均找到比自己大的元素。
还没结束,此时index = 3是下次要找比自己大元素的下标,所以3入栈,此时 栈【3】
循环。。。。
上面(1,2)步,是nums[i]=nums[j]的情况,(2,3)步,是nums[i]>nums[j]的情况,(3,4)步时nums[i]<nums[j]的情况,验证了一下可行性
总体一句话:
栈中的元素是:已经遍历了,但是还没找到比自己大元素的下标
将要入栈的是:要比较的目标下标,也是还没找到比自己大元素的下标,是下一次比较的起点,无论如何必须入栈
相信你复制下面代码debug一下过程,会有更深刻的印象:
代码:
public static int[] nextGreaterElements(int[] nums) {
int length = nums.length;
int[] res = new int[length];
Arrays.fill(res,-1);
Stack<Integer> stack = new Stack<>();
for(int i =0;i<length*2;i++){
int index = i%length;
while (!stack.isEmpty()&&nums[stack.peek()]<nums[index]){
res[stack.pop()] = nums[index];
}
stack.push(index);
}
return res;
}
时间复杂度n,是不是有了方法就很简单的一道中等题?
当然,找下一个比自己大元素还有经典的双指针法,不过时间复杂度n2,以上

本文解析了如何使用单调栈算法解决LeetCode中的经典问题,通过实例演示如何找出循环数组中每个元素的下一个更大元素。理解栈的操作和何时入栈、出栈,有助于提升算法理解。

被折叠的 条评论
为什么被折叠?



