下一个更大元素I496
题干
nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。
给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。
对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -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] <= 104
nums1和nums2中所有整数 互不相同
nums1 中的所有整数同样出现在 nums2 中
进阶:你可以设计一个时间复杂度为 O(nums1.length + nums2.length) 的解决方案吗?
思路
单调栈,只需要发现在Nums2[j]后面有没有更大的元素,就可以将nums2[j]记录下来,不需要记录此元素和目标元素的距离值。
stk.pop(); 必须放在 if 语句外面,因为无论栈顶元素是否存在于 nums1 中(即是否要记录答案),它都已经找到了右边第一个更大的元素(即当前的 nums2[j])。既然它已经“完成任务”,就应该从栈中弹出,以便后续元素可以正确比较。
单调栈的核心规则:栈中存放的是尚未找到右边更大元素的下标。当遇到一个比栈顶大的数 nums2[j] 时,说明栈顶元素找到了它的右边第一个更大值,因此它必须被弹出栈,不再参与后续比较。
如果不弹出不属于 nums1 的元素:
- 这些元素虽然不需要记录答案,但它们仍然占据着栈中的位置,且其值比当前元素小。
- 后续遍历中,如果遇到更大的数,这些“过期”元素会干扰判断:比如它们本应被移除,却仍然留在栈中,导致 while 循环条件可能错误地继续触发,或者阻塞后面更小的元素入栈,破坏栈的递减性。
- 更严重的是,如果始终不弹出,程序可能陷入无限循环(如你之前遇到的超时问题),因为 while 条件一直为真却无法改变栈顶。
正确逻辑:在 while 循环中,只要当前元素大于栈顶,就要处理栈顶并弹出。处理时,先检查栈顶元素是否属于 nums1,若是则更新答案;然后无论是否更新,都要 pop 掉它。这样栈才能保持单调递减,且所有元素都能被正确遍历。
题解
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
vector<int> ans(nums1.size(),-1);
if(nums1.size()==0) return ans;
stack<int> stk;
unordered_map<int, int> record;
stk.push(0);
for(int i=0;i<nums1.size();++i){
record[nums1[i]]=i;
}
for(int j=0;j<nums2.size();++j){
while(!stk.empty()&&nums2[j]>nums2[stk.top()]){
if(record.count(nums2[stk.top()])!=0){
ans[record[nums2[stk.top()]]] = nums2[j];
}
stk.pop();
}
stk.push(j);
}
return ans;
}
};