一、题目描述:
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
示例
输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
注意: 输入数组的长度不会超过 10000。
二、思路分析:
一般我们会想到暴力法,对数组中每个元素都向后去寻找比它更大的元素,时间复杂度 O(N^2) 会超时。
通过单调栈,来获取下一个更大元素
-
可以使用单调栈解决本题。单调栈中保存的是数组nums的下标,从栈底到栈顶的下标在数组 nums 中对应的值是单调递减的。维护一个单调递减栈。
-
每次移动到数组中的一个新的位置i,我们就将当前单调栈中所有对应值小于 nums[i]的下标弹出单调栈,这些值的下一个更大元素就是nums[i]。
-
然后将位置 i 入栈。
来模拟以下过程
- new Stack < >
- nums[0]是1, Stack为空,下标入栈,Stack< 0 >,
- nums[1]是2, Stack不空,nums[栈顶元素值(现在是0)]=1<2,如果入栈,不满足单调递减栈,那么就把下标0弹出,下标1入栈。这时弹出的(0)对应的nums[0]元素的[下一个更大元素]就是2。下标1入栈。
- nums[2]是1,Stack不空, nums[栈顶元素(现在是1)]=2>1, 如果入栈,符合单调递减栈。
如果理解困难,再举例一试 nums={5,4,6}, 当5,4的下标依次入栈时,符合栈单调递减,但是当6的下标入栈时候,6比他们都大,他们都的出栈,否则不满足单调递减。6把他们都逼走了。简而言之,nums[被逼走的下标]的下一个更大元素就是把他们逼走的元素。
那么问题又来了,一遍循环肯定不够,数组的最后元素怎么办,说好的循环数组呢?
办法就是复制数组的前n-1个元素,到nums的后面。这样我们就可以将这个新序列当作普通序列,用单调栈的方法来求解。
三、AC 代码:
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
stack<int> stack;
vector<int> res(nums.size(), -1);
for(int i = 0; i <= nums.size()*2; i++)
{
while(!stack.empty() && nums[i % nums.size()] > nums[stack.top()])
{
res[stack.top()] = nums[i % nums.size()];
stack.pop();
}
if(i < nums.size()){
stack.push(i);
}
}
return res;
}
};
四、总结:
暴力法求解时间复杂度O(N^2), 采用单调栈时间复杂度O(N)。
本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情