题目链接:https://leetcode.cn/problems/next-greater-element-iv/
题目大意:给出一串数列nums[]
,要求给出每个元素对应的【在其右边的】【第二个】【比它大的元素】,如果这个值不存在,填上-1
思路:暴力做肯定会超时,刚开始想着从后往前做(因为倒数两个元素对应的值肯定是-1
),但发现元素并没有被排过序,需要维护的东西有点多。不愧是困难题…
看了题解才知道要用单调栈做。并且思路清奇。单调栈中存放的是元素的下标。需要维护两个单调递减的栈:
s0
:表示里面的元素的右边没有比它大的s1
:表示里面的元素的右边有一个比它大的
每次扫描到nums[i]
,首先将其与s1
栈顶的元素对比,如果nums[i]
更大,说明nums[i]
就是【右边的】【第二个】【比它大的元素】,栈顶元素弹出,填入答案。这个过程应该是个while
循环,保证所满足上述情况的栈顶元素都被弹出。
while(!s1.empty() && nums[i] > nums[s1.back()]) {
answer[s1.back()] = nums[i];
s1.pop_back();
}
再将其与s0
栈顶元素对比,如果nums[i]
更大,说明栈顶元素现在【右边有一个比它大的】,要将其移到s1
中了。弹出。同样while
循环到所有满足上述情况的栈顶元素都被弹出。这些被弹出的元素保存在临时数组to_move[]
里,随后保持单调性移动到s1
中。
while(!s0.empty() && nums[i] > nums[s0.back()]) {
to_move.push_back(s0.back());
s0.pop_back();
}
for (int j = to_move.size()-1; j >= 0; j--)
s1.push_back(to_move[j]);
扫描完后,将当前元素【的下标】塞进s0
中(因为它右边还未扫描,还没有任何东西,因此肯定是属于s0
的)
s0.push_back(i);
完整代码
class Solution {
public:
vector<int> secondGreaterElement(vector<int>& nums) {
int n = nums.size();
vector<int> answer(n, -1);
vector<int> s0, s1;
for (int i = 0; i < n; i++) {
vector<int> to_move;
while(!s1.empty() && nums[i] > nums[s1.back()]) {
answer[s1.back()] = nums[i];
s1.pop_back();
}
while(!s0.empty() && nums[i] > nums[s0.back()]) {
to_move.push_back(s0.back());
s0.pop_back();
}
for (int j = to_move.size()-1; j >= 0; j--)
s1.push_back(to_move[j]);
s0.push_back(i);
}
return answer;
}
};