思路
最粗暴的方法就是O(n²),这题也没卡暴力,可以击败5%混过去,但可以用单调栈来优化。
众所周知,单调栈致力于解决“寻找首个大于(小于)当前位置的值”,要明白单调栈的优势,就要搞清楚它的原理。
常规方法慢在挨个枚举,对每个元素都去一个个的找满足条件的值,那自然是慢的。如果说暴力的思路是“用每个值去找答案”,那单调栈的思路可以形象地理解为“让答案自己去找值”。
就本题而言,单调栈中存的是还没有找到答案的下标,他们自底向上严格上升。在遍历中,如果当前栈顶下标对应的值比nums[i]小,那么nums[i]就是当前值答案,将nums[i]计入ans中并弹出当前下标即完成一次操作。
这样做的正确性是显然地,因为有栈的后入先出特性做保证,当前nums[i]一定最有可能是栈顶元素的答案。
更具体地,因为这题是循环数组,所以需要遍历两次,初始化ans数组为全-1就可以避免最后再来为栈内未出栈的元素赋-1的操作。
代码
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
const int n = nums.size();
stack<int> stk;
vector<int> ans(n, -1);
stk.push(0);
for (int i = 0; i < n; i++) {
while(!stk.empty() && nums[stk.top()] < nums[i]) {
ans[stk.top()] = nums[i];
stk.pop();
}
stk.push(i);
}
for (int i = 0; i < n; i++) {
while(!stk.empty() && nums[stk.top()] < nums[i]) {
ans[stk.top()] = nums[i];
stk.pop();
}
stk.push(i);
}
return ans;
}
};