题目:
思路与解法:
1、如果是暴力法,只需要遍历就可以了,但是那样的话时间复杂度就是O(N^2);
2、可以把这几个数字,抽象成为高度不一样的柱子;
3、寻找的过程,就是从当前柱子去看,被后面的哪一个柱子首先挡住
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()循环的条件控制,二是正确读取对应的值(取余%);这样节约了空间,还起了一样的效果;