下一个更大元素 II
leetcode 503. 下一个更大元素 II
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/next-greater-element-ii
题目描述
给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素 。
数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1 。
示例 1:
输入: nums = [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
示例 2:
输入: nums = [1,2,3,4,3]
输出: [2,3,4,-1,4]
单调栈
对于「找最近一个比当前值大/小」的问题,都可以使用单调栈来解决。
单调栈就是在栈的基础上维护一个栈内元素单调。
在理解单调栈之前,我们先回想一下「朴素解法」是如何解决这个问题的。
对于每个数而言,我们需要遍历其右边的数,直到找到比自身大的数,这是一个的做法。之所以是
,是因为每次找下一个最大值,我们是通过「主动」遍历来实现的。
而如果使用的是单调栈的话,可以做到的复杂度,我们将当前还没得到答案的下标暂存于栈内,从而实现「被动」更新答案。
也就是说,栈内存放的永远是还没更新答案的下标。
具体的做法是:
每次将当前遍历到的下标存入栈内,将当前下标存入栈内前,检查一下当前值是否能够作为栈内位置的答案(即成为栈内位置的「下一个更大的元素」),如果可以,则将栈内下标弹出。
如此一来,我们便实现了「被动」更新答案,同时由于我们的弹栈和出栈逻辑,决定了我们整个过程中栈内元素单调。
还有一些编码细节,由于我们要找每一个元素的下一个更大的值,因此我们需要对原数组遍历两次,对遍历下标进行取余转换。
以及因为栈内存放的是还没更新答案的下标,可能会有位置会一直留在栈内(最大值的位置),因此我们要在处理前预设答案为 -1。而从实现那些没有下一个更大元素(不出栈)的位置的答案是 -1。
class Solution {
public int[] nextGreaterElements(int[] nums) {
int n = nums.length;
int[] ans = new int[n];
Arrays.fill(ans, -1);
Deque<Integer> d = new ArrayDeque<>();
for (int i = 0; i < n * 2; i++) {
while (!d.isEmpty() && nums[i % n] > nums[d.peekLast()]) {
int u = d.pollLast();
ans[u] = nums[i % n];
}
d.addLast(i % n);
}
return ans;
}
}
单调栈加数组优化栈结构
用数组模拟栈结构,效率会更高.
/**
* 单调栈 + 数组优化
* @param nums
* @return
*/
public int[] nextGreaterElements(int[] nums) {
int n = nums.length;
//记录答案
int[]ans = new int[n];
Arrays.fill(ans,-1);
//用数组来代替栈结构,会让时间变得更快
int[] stack = new int[2 * n];
int size = 0;
for (int i = 0; i < (2 * n);i++){
while (size != 0 && nums[i % n] > nums[stack[size - 1]]){
ans[stack[--size]] = nums[i % n];
}
stack[size++] = i % n;
}
return ans;
}