下一个更大元素
题目
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
方法一:单调栈 + 循环数组
思路及算法
我们可以使用单调栈解决本题。单调栈中保存的是下标,从栈底到栈顶的下标在数组 \textit{nums}nums 中对应的值是单调不升的。
每次我们移动到数组中的一个新的位置 ii,我们就将当前单调栈中所有对应值小于 \textit{nums}[i]nums[i] 的下标弹出单调栈,这些值的下一个更大元素即为 \textit{nums}[i]nums[i](证明很简单:如果有更靠前的更大元素,那么这些位置将被提前弹出栈)。随后我们将位置 ii 入栈。
但是注意到只遍历一次序列是不够的,例如序列 [2,3,1][2,3,1],最后单调栈中将剩余 [3,1][3,1],其中元素 [1][1] 的下一个更大元素还是不知道的。
一个朴素的思想是,我们可以把这个循环数组「拉直」,即复制该序列的前 n-1n−1 个元素拼接在原序列的后面。这样我们就可以将这个新序列当作普通序列,用上文的方法来处理。
而在本题中,我们不需要显性地将该循环数组「拉直」,而只需要在处理时对下标取模即可。
作者:LeetCode-Solution 链接:leetcode-cn.com/problems/ne… 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
代码
var nextGreaterElements = function(nums) {
const n = nums.length;
const ret = new Array(n).fill(-1);
const stk = [];
for (let i = 0; i < n * 2 - 1; i++) {
while (stk.length && nums[stk[stk.length - 1]] < nums[i % n]) {
ret[stk[stk.length - 1]] = nums[i % n];
stk.pop();
}
stk.push(i % n);
}
return ret;
};
复杂度分析
时间复杂度: O(n)O(n),其中 nn 是序列的长度。我们需要遍历该数组中每个元素最多 22 次,每个元素出栈与入栈的总次数也不超过 44 次。
空间复杂度: O(n)O(n),其中 nn 是序列的长度。空间复杂度主要取决于栈的大小,栈的大小至多为 2n-12n−1。