Easy
题目描述
数组中某个元素 x 的下一个更大元素是指在同一个数组中,x 右边的第一个比 x 更大的元素。
给你两个没有重复元素的数组 nums1 和 nums2,其中 nums1 是 nums2 的子集。
对于 nums1 中的每个元素,在 nums2 中找到它右边第一个比它大的元素。如果不存在,则该查询的答案是 -1。
返回一个长度为 nums1.length 的数组 ans,其中 ans[i] 是上述查询的答案。
示例 1:
输入:nums1 = [4,1,2], nums2 = [1,3,4,2]
输出:[-1,3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:
- 4 在 nums2 = [1,3,4,2] 中,没有下一个更大的元素,所以答案是 -1。
- 1 在 nums2 = [1,3,4,2] 中,下一个更大的元素是 3。
- 2 在 nums2 = [1,3,4,2] 中,没有下一个更大的元素,所以答案是 -1。
示例 2:
输入:nums1 = [2,4], nums2 = [1,2,3,4]
输出:[3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:
- 2 在 nums2 = [1,2,3,4] 中,下一个更大的元素是 3。
- 4 在 nums2 = [1,2,3,4] 中,没有下一个更大的元素,所以答案是 -1。
提示:
- 1 <= nums1.length <= nums2.length <= 1000
- 0 <= nums1[i], nums2[i] <= 10^4
- nums1 和 nums2 中所有整数互不相同
- nums1 中的所有整数同样出现在 nums2 中
进阶: 你可以设计一个时间复杂度为 O(nums1.length + nums2.length) 的解决方案吗?
解题思路
这道题有两种主要解法:暴力查找和单调栈。
方法一:暴力查找 对于 nums1 中的每个元素,先在 nums2 中找到它的位置,然后从该位置开始向右寻找第一个更大的元素。时间复杂度为 O(n*m),其中 n 和 m 分别是两个数组的长度。
方法二:单调栈(推荐) 这是最优解法,利用单调递减栈预处理 nums2 中每个元素的下一个更大元素:
- 使用哈希表存储每个元素的下一个更大元素映射关系
- 遍历 nums2,维护一个单调递减栈:
- 如果当前元素大于栈顶元素,说明找到了栈顶元素的下一个更大元素
- 将所有小于当前元素的栈顶元素弹出,并记录映射关系
- 将当前元素入栈
- 遍历 nums1,通过哈希表查找每个元素的下一个更大元素
这种方法只需要遍历一次 nums2 和一次 nums1,时间复杂度为 O(n+m),满足进阶要求。单调栈是解决"下一个更大/更小元素"问题的经典数据结构。
代码实现
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int, int> nextGreater;
stack<int> stk;
// 使用单调栈找到nums2中每个元素的下一个更大元素
for (int num : nums2) {
while (!stk.empty() && stk.top() < num) {
nextGreater[stk.top()] = num;
stk.pop();
}
stk.push(num);
}
// 构建结果数组
vector<int> result;
for (int num : nums1) {
result.push_back(nextGreater.count(num) ? nextGreater[num] : -1);
}
return result;
}
};
class Solution:
def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
next_greater = {}
stack = []
# 使用单调栈找到nums2中每个元素的下一个更大元素
for num in nums2:
while stack and stack[-1] < num:
next_greater[stack.pop()] = num
stack.append(num)
# 构建结果数组
return [next_greater.get(num, -1) for num in nums1]
public class Solution {
public int[] NextGreaterElement(int[] nums1, int[] nums2) {
Dictionary<int, int> nextGreater = new Dictionary<int, int>();
Stack<int> stack = new Stack<int>();
// 使用单调栈找到nums2中每个元素的下一个更大元素
foreach (int num in nums2) {
while (stack.Count > 0 && stack.Peek() < num) {
nextGreater[stack.Pop()] = num;
}
stack.Push(num);
}
// 构建结果数组
int[] result = new int[nums1.Length];
for (int i = 0; i < nums1.Length; i++) {
result[i] = nextGreater.ContainsKey(nums1[i]) ? nextGreater[nums1[i]] : -1;
}
return result;
}
}
var nextGreaterElement = function(nums1, nums2) {
const nextGreater = new Map();
const stack = [];
// 使用单调栈找到nums2中每个元素的下一个更大元素
for (const num of nums2) {
while (stack.length > 0 && stack[stack.length - 1] < num) {
nextGreater.set(stack.pop(), num);
}
stack.push(num);
}
// 构建结果数组
return nums1.map(num => nextGreater.has(num) ? nextGreater.get(num) : -1);
};
复杂度分析
| 解法 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 单调栈 | O(n + m) | O(n) |
| 暴力查找 | O(n × m) | O(1) |
其中 n 为 nums2 的长度,m 为 nums1 的长度。单调栈解法是最优解,每个元素最多入栈和出栈一次。
相关题目
503. Next Greater Element II (Medium)
556. Next Greater Element III (Medium)
739. Daily Temperatures (Medium)
2104. Sum of Subarray Ranges (Medium)
2487. Remove Nodes From Linked List (Medium)
2996. Smallest Missing Integer Greater Than Sequential Prefix Sum (Easy)