LC-2454.下一个更大元素IV

题目描述

leetcode 困难题

给你一个下标从 0 开始的非负整数数组 nums 。对于 nums 中每一个整数,你必须找到对应元素的 第二大 整数。

如果 nums[j] 满足以下条件,那么我们称它为 nums[i] 的 第二大 整数:

j > i
nums[j] > nums[i]
恰好存在 一个 k 满足 i < k < j 且 nums[k] > nums[i] 。
如果不存在 nums[j] ,那么第二大整数为 -1 。

比方说,数组 [1, 2, 4, 3] 中,1 的第二大整数是 4 ,2 的第二大整数是 3 ,3 和 4 的第二大整数是 -1 。
请你返回一个整数数组 answer ,其中 answer[i]是 nums[i] 的第二大整数。

示例1:

1
2
3
4
5
6
7
8
9
输入:nums = [2,4,0,9,6]
输出:[9,6,6,-1,-1]
解释:
下标为 0 处:2 的右边,4 是大于 2 的第一个整数,9 是第二个大于 2 的整数。
下标为 1 处:4 的右边,9 是大于 4 的第一个整数,6 是第二个大于 4 的整数。
下标为 2 处:0 的右边,9 是大于 0 的第一个整数,6 是第二个大于 0 的整数。
下标为 3 处:右边不存在大于 9 的整数,所以第二大整数为 -1 。
下标为 4 处:右边不存在大于 6 的整数,所以第二大整数为 -1 。
所以我们返回 [9,6,6,-1,-1] 。

提示1:

1
2
1 <= nums.length <= 10^5
0 <= nums[i] <= 10^9

单调栈+优先队列

先考虑找 $nums[i]$ 的第一大元素,显然我们可以通过单调栈求出,那么此时在第一大元素后面第一个大于 $nums[i]$ 的数即为第二大元素。

具体来说,顺序遍历数组,维护一个栈顶到栈底单调递增的单调栈,对于每个 $nums[i]$ ,如果大于栈顶元素,则当前元素为栈顶元素的第一大元素,弹出该栈顶,此时显然右边第一个大于栈顶的元素为栈顶的第二大元素。那么类似找第一个元素的过程,我们可以第二个单调栈保存所弹出的元素,后续遍历过程中只要某个元素 $nums[i]$ 大于第二个单调栈的栈顶,说明 $nums[i]$ 为第二个单调栈的栈顶的第二大元素。

需要注意的是,类似第一个单调栈,第二个单调栈也需要维护栈顶到栈底单调递增的性质,一种方法是在对第一个栈做弹出时,使用一个临时栈来保存所弹出顺序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public int[] secondGreaterElement(int[] nums) {
int n = nums.length;
int[] ans = new int[n];
Arrays.fill(ans, -1);
Deque<Integer> monoStack = new ArrayDeque<>();
Deque<Integer> secondMonoStack = new ArrayDeque<>();
for (int i = 0; i < n; i++) {
while(!secondMonoStack.isEmpty() && nums[secondMonoStack.peek()] < nums[i]){
ans[secondMonoStack.pop()] = nums[i];
}
Deque<Integer> temp = new ArrayDeque<>();
while (!monoStack.isEmpty() && nums[monoStack.peek()] < nums[i]) {
temp.push(monoStack.pop());
}
monoStack.push(i);
while(!temp.isEmpty()){
secondMonoStack.push(temp.pop());
}
}
return ans;
}
}

也可以直接用优先队列来省去一些代码,但对应时间复杂度会多一个 $log$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public int[] secondGreaterElement(int[] nums) {
int n = nums.length;
int[] ans = new int[n];
Arrays.fill(ans, -1);
Deque<Integer> monoStack = new ArrayDeque<>();
PriorityQueue<Integer> secondHigherQueue = new PriorityQueue<>((a, b) -> nums[a] - nums[b]);
for (int i = 0; i < n; i++) {
while(!secondHigherQueue.isEmpty() && nums[secondHigherQueue.peek()] < nums[i]){
ans[secondHigherQueue.poll()] = nums[i];
}
while (!monoStack.isEmpty() && nums[monoStack.peek()] < nums[i]) {
secondHigherQueue.offer(monoStack.pop());
}
monoStack.push(i);
}
return ans;
}
}

LC-2454.下一个更大元素IV
https://wecgwm.github.io/2023/03/10/LC-2454-下一个更大元素IV/
作者
yichen
发布于
2023年3月10日
许可协议