力扣【下一个更大元素】leetcode-503.下一个更大元素 Ⅱ:单调栈解法+循环数组解法

题目:

在这里插入图片描述

思路与解法:

1、如果是暴力法,只需要遍历就可以了,但是那样的话时间复杂度就是O(N^2);
2、可以把这几个数字,抽象成为高度不一样的柱子;
3、寻找的过程,就是从当前柱子去看,被后面的哪一个柱子首先挡住

图片转载自labuladong)

4、使用单调栈,每一次有新元素加入的时候,进行处理,保持栈内的元素是单调的;这样的很巧妙;栈是先进后出的,而且是找“第一个大的”,就是栈中最小的;所以,使用一个单调减的单调栈
5、由于使用栈,栈是先进后出的;从后面开始遍历,倒过来入栈,最后栈出来的顺序才是和原数组的顺序是一样的;
6、单调栈中存的是什么?
动态的看,是:(从当前位置)从前往后,第一个看见的柱子,第二个看见的柱子,第三个看见的柱子····如此;因为两个高个子柱子中间的那一个柱子,从前面肯定是看不到的;
7、循环数组的巧妙处理:做好for()循环的条件控制,i = 2*n - 1; 看起来就是遍历了两次数组一样;做好正确读取对应的值(取余%) nums[i%n];这样就没必要去双倍扩充数组了!

由此得到如下框架:

for(从后往前遍历) {
    
      循环数组处理:i = 2*n - 1;  nums[i%n]
	while () {
    
    
	新元素进来,排序一次;
	被挡住看不见的就出栈
	}
	判断 {
    
    
	如果栈空,没更大的了,输出 -1;
	否则;输出栈顶元素
	}	
	新元素来,进栈
}

代码:

class Solution {
    
    
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
    
    
        int n = nums.size();
        vector<int> res(n);
        stack<int> s;  //单调栈解法  和 739题每日温度相似;多了循环数组的处理
        //不去增倍数组,使用循环数组;
        //循环数组,只是 索引 i 变大了,所以for 循环里面效果似乎是两次
        //处理的时候,nums[i%n] 就是读取到真的数字
        for (int i = 2 * n - 1; i >= 0; i --) {
    
    
            while (!s.empty() && s.top()<= nums[i%n] ) {
    
    
                s.pop();//反正挡住了,就出栈,保持单调
            }
            res[i%n] = s.empty() ? -1 : s.top();
            s.push(nums[i%n]);//进新的 以便后一步判断
        }
        return res;
    }
};

结果:

在这里插入图片描述

总结:

1、感觉最重要的,首先就是有这样一个抽象的思维,好比建模一样,把每一个数字,抽象成“高低不同的柱子”,然后想象成在前面投影,后面的第一个可以看见的柱子,就是需要找的那一个。
2、随后是对于 “栈” 的理解;栈是先进去后出来的,所以从后遍历;其中还要做好对栈进行处理,保持是一个单调的栈
3、循环数组的巧妙处理,一是只需要做好for()循环的条件控制,二是正确读取对应的值(取余%);这样节约了空间,还起了一样的效果;

猜你喜欢

转载自blog.csdn.net/qq_43473694/article/details/109549054