下一个更大元素
下一个更大元素1
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 。
思路:使用单调栈,首先要想单调栈是从大到小还是从小到大。
在本题中:栈顶到栈底的顺序,要从小到大,也就是保持栈里的元素为递增顺序。只要保持递增,才能找到右边第一个比自己大的元素。
分析三种情况:
- 当前遍历的元素nums2[i]小于栈顶元素nums2[stack.peek()]的情况,此时满足递增栈(栈头到栈底的顺序),所以直接入栈。
- 当前遍历的元素nums2[i]等于栈顶元素nums2[stack.peek()]的情况,如果相等的话,依然直接入栈,因为要求的是右边第一个比自己大的元素,而不是大于等于!
- 当前遍历的元素nums2[i]大于栈顶元素nums2[stack.peek()]的情况,此时如果入栈就不满足递增栈了,这也是找到右边第一个比自己大的元素的时候。需要判断栈顶元素是否在nums1里出现过,(注意栈里的元素是nums2的索引下标),如果出现过,开始记录结果。
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
int len1 = nums1.length, len2 = nums2.length;
int[] res = new int[len1];
Arrays.fill(res, -1);
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < len1; i++) {
map.put(nums1[i], i);//key为nums1[i],value为其下标
}
//从栈顶到栈底为递增,也就是说,栈底的元素最大
Stack<Integer> stack = new Stack<>();
stack.push(0);
for (int i = 1; i < len2; i++) {
if (nums2[stack.peek()] > nums2[i]) {//栈顶元素大于当前元素,则压入栈
stack.push(i);
} else {//栈顶元素小于当前元素
while (!stack.isEmpty() && nums2[stack.peek()] < nums2[i]) {
//若栈顶元素在nums1数组中,则根据该元素得到其在nums1中的坐标,且该位置上的返回值应为nums2[i]
if (map.containsKey(nums2[stack.peek()])) {
int index = map.get(nums2[stack.peek()]);
res[index] = nums2[i];
}
stack.pop();//栈顶元素弹出栈
}
stack.push(i);//直到stack为空,或栈顶元素大于nums2[i],将其压入栈
}
}
return res;
}
}
下一个更大元素2
给定一个循环数组 nums
( nums[nums.length - 1]
的下一个元素是 nums[0]
),返回 nums
中每个元素的 下一个更大元素 。
数字 x
的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1
。
示例 1:
输入: nums = [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
class Solution {
public int[] nextGreaterElements(int[] nums) {
int len = nums.length;
int[] res = new int[len];
Arrays.fill(res, -1);
Stack<Integer> stack = new Stack<>();
stack.push(0);
for (int i = 1; i < 2 * len; i++) {//遍历两边数组即可
while (!stack.isEmpty() && nums[stack.peek()] < nums[i % len]) {
res[stack.peek()] = nums[i % len];
stack.pop();
}
stack.push(i % len);
}
return res;
}
}