每日温度
请根据每日 气温
列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0
来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73]
,你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]
。
提示:气温
列表长度的范围是 [1, 30000]
。每个气温的值的均为华氏度,都是在 [30, 100]
范围内的整数。
方法一:从前往后遍历
递减栈(含相同元素)
栈中存的是元素的下标,栈中元素都还没找到大于它的
如果当前元素比栈顶元素大,那么说明栈顶元素找到了大于它的温度,将它出栈,直至栈为空或者栈顶元素不比当前元素大,再将当前元素入栈
如果栈为空,或者当前元素不比栈顶元素大,说明栈顶元素还没有找到比它大的,将当前元素入栈
public int[] dailyTemperatures(int[] T) {
int[] ans = new int[T.length];
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < T.length; i++) {
while(!stack.isEmpty() && T[stack.peek()] < T[i]) {
int index = stack.pop();
ans[index] = i - index;
}
stack.push(i);
}
return ans;
}
方法二:从后往前遍历
栈中元素是当前位置右边的元素,在其中寻找能不能找到一个比它大的元素,找到的一定是第一个,将比它小的元素出栈
public int[] dailyTemperatures(int[] temperatures) {
int n = temperatures.length;
Stack<Integer> stack = new Stack<>();
int[] res = new int[n];
for (int i = n - 1; i >= 0; i--) {
while (!stack.isEmpty() && temperatures[i] >= temperatures[stack.peek()]) {
stack.pop();
}
res[i] = stack.isEmpty() ? 0 : stack.peek() - i;
stack.push(i);
}
return res;
}
下一个更大元素 I
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 。
方法一:暴力
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
int m = nums1.length, n = nums2.length;
int[] res = new int[m];
for (int i = 0; i < m; i++) {
int j = 0;
while (j < n && nums2[j] != nums1[i]) {
j++;
}
j++;
while (j < n && nums2[j] <= nums1[i]) {
j++;
}
res[i] = j == n ? -1 : nums2[j];
}
return res;
}
方法二:单调栈+hash
先处理nums,得到每个元素第一个比它大的元素,然后由于元素不重复,使用hash表获得到nums1
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
int m = nums1.length, n = nums2.length;
int[] res = new int[m];
Map<Integer, Integer> map = new HashMap<>();
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < n; i++) {
while (!stack.isEmpty() && nums2[stack.peek()] < nums2[i]) {
map.put(nums2[stack.pop()], nums2[i]);
}
stack.push(i);
}
for (int i = 0; i < m; i++) {
res[i] = map.getOrDefault(nums1[i], -1);
}
return res;
}
也可以从后往前遍历:
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
int m = nums1.length, n = nums2.length;
int[] res = new int[m];
Map<Integer, Integer> map = new HashMap<>();
Stack<Integer> stack = new Stack<>();
for (int i = n - 1; i >= 0; i--) {
while (!stack.isEmpty() && nums2[i] > stack.peek()) {
stack.pop();
}
map.put(nums2[i], stack.isEmpty() ? -1 : stack.peek());
stack.push(nums2[i]);
}
for (int i = 0; i < m; i++) {
res[i] = map.get(nums1[i]);
}
return res;
}
下一个更大元素 II
给定一个循环数组 nums
( nums[nums.length - 1]
的下一个元素是 nums[0]
),返回 nums
中每个元素的 下一个更大元素 。
数字 x
的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1
。
示例 1:
输入: nums = [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数;
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。
需要处理的是循环数组,注意到只遍历一次序列是不够的,例如序列 [2,3,1][2,3,1],最后单调栈中将剩余 [3,1],其中元素 [1] 的下一个更大元素还是不知道的。
一个朴素的思想是,我们可以把这个循环数组「拉直」,即复制该序列的前 n−1 个元素拼接在原序列的后面。这样我们就可以将这个新序列当作普通序列,用上文的方法来处理。而在本题中,我们不需要显性地将该循环数组「拉直」,而只需要在处理时对下标取模即可。
public int[] nextGreaterElements(int[] nums) {
int n = nums.length;
int[] res = new int[n];
Arrays.fill(res, -1);
Stack<Integer> stack = new Stack<>();
for (int i = 0; i < 2 * n - 1; i++) {
while (!stack.isEmpty() && nums[i % n] > nums[stack.peek()]) {
res[stack.pop() % n] = nums[i % n];
}
stack.push(i % n);
}
return res;
}