「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战」
题目描述
给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
示例 1:
输入: [1,2,1] 输出: [2,-1,2] 解释: 第一个 1 的下一个更大的数是 2; 数字 2 找不到下一个更大的数; 第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
注意: 输入数组的长度不会超过 10000。
解法1:单调栈
具体实现:
- 遍历数组,为了保证所有数据全部探寻到,所有需要遍历两次,nums.length * 2,用取模处理越界问题。
- 需要采用单调栈,并且从栈顶到栈底,单调递减
- 递减的单调栈,可以保证外部元素大于栈顶元素时,可以保证出栈的元素都比外部元素。
public int[] nextGreaterElements(int[] nums) {
int len = nums.length;
int[] res = new int[len];
Arrays.fill(res, -1);
Deque<Integer> stack = new LinkedList<>();
for (int i = 0; i < len * 2 - 1; i++) {
while (!stack.isEmpty() && nums[stack.peek()] < nums[i % len]) {
res[stack.pop()] = nums[i % len];
}
stack.push(i % len);
}
return res;
}
解法2:动态规划
class Solution {
public int[] nextGreaterElements(int[] nums) {
int n=nums.length;
int[] a=new int[n];
Arrays.fill(a,Integer.MIN_VALUE);
for(int i=n-1;i>=0;i--){
int j;
for(j=1;j<n;j++){
int p=(i+j)%n;
if(nums[p]>nums[i]){
a[i]=nums[p];
break;
}
else if(a[p]>nums[i]){
a[i]=a[p];
break;
}
}
if(j==n){
a[i]=-1;
}
}
return a;
}
}
总结
其实我们可以发现,大体思路上,就是入栈前先排个序。如果当前元素比栈顶元素小,正常入栈。如果当前元素比栈顶元素大,那么关键点就来了,说明当前元素至少是栈顶元素的下一个更大元素,将栈顶元素出栈,当前元素再和接下来的栈顶元素比较,小->入栈,大->继续栈顶出栈,出栈的这些就算是找到下一个更大元素了,更新即可。这个单调栈保存的其实是数组下标。