第六十天| 第十章 单调栈 part01 739. 每日温度 496. 下一个更大元素I
一、739. 每日温度
-
题目链接:https://leetcode.cn/problems/daily-temperatures/submissions/
-
题目介绍:
-
给定一个整数数组
temperatures
,表示每天的温度,返回一个数组answer
,其中answer[i]
是指对于第i
天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用0
来代替。示例 1:
输入: temperatures = [73,74,75,71,69,72,76,73] 输出: [1,1,4,2,1,1,0,0]
-
-
思路:
-
(1)为什么要使用单调栈呢?
- 单调栈一般用于解决这类问题:
- 通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。时间复杂度为O(n)。
- 单调栈一般用于解决这类问题:
-
(2)在使用单调栈的时候要明确以下内容:
-
第一、单调栈中存放的是什么元素?
- 因为本题中所求的是数组右侧第一个比当前数更大值的距离,为了方便求解,单调栈中存放的是遍历过的元素的下标。
-
第二、什么时候压栈,什么时候弹栈,什么时候记录结果?
- 使用单调栈,主要是判断以下三种情况:
-
当前遍历的元素T[i]小于栈顶元素T[stack.peek()]的情况
- 如果遍历的当前元素等于或者小于栈顶元素,直接压栈即可。
-
当前遍历的元素T[i]等于栈顶元素T[stack.peek()]的情况
- 如果遍历的当前元素等于或者小于栈顶元素,直接压栈即可。
-
当前遍历的元素T[i]大于栈顶元素T[stack.peek()]的情况
- 如果遍历的当前元素大于栈顶元素(栈顶下标对应的元素),记录结果result[stack.peek()] = 当前遍历的下标 - stack.peek()。记录完结果之后,栈顶元素弹出,当前遍历的元素压栈。
-
- 使用单调栈,主要是判断以下三种情况:
-
第三、既然是单调的,什么情况下单调递增,什么情况下单调递减?
- 从第二个问题可以看出,因为本题求得是:右边第一个大于当前元素的距离。因此单调栈中的元素是单调递增的
- 如果求一个元素右边第一个更小元素,单调栈就是递减的。
-
-
-
代码:
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
// 定义结果数组
int[] result = new int[temperatures.length];
// 定义单调栈
Deque<Integer> stack = new LinkedList<>();
stack.push(0);
for (int i = 1; i < temperatures.length; i++) {
// 如果当前遍历元素小于或等于栈顶元素
if (temperatures[i] <= temperatures[stack.peek()]) {
stack.push(i);
}else {
while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) {
result[stack.peek()] = i - stack.peek();
stack.pop();
}
stack.push(i);
}
}
return result;
}
}
二、496. 下一个更大元素I
-
题目链接:https://leetcode.cn/problems/next-greater-element-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 。
-
-
思路:
- 本题需要一个result数组(和数组一等大),一个单调栈,一个map集合。
- result数组:
- 记录nums1中该元素找到的在nums2中右侧的第一个比当前元素大的元素。
- 因此,result.length和nums1.length相等
- map:
- map的key是nums1的值,value是nums1的下标
- 题目中强调了数组没有重复,所以不用考虑key重复
- 单调栈:
- 因为是在nums2中寻找右面比当前值大的元素,因此单调栈是遍历nums2构建的
- 单调栈中的逻辑和上题一样,分为三种i情况讨论:
- 第一种:nums2[i] < nums2[stack.peek()]
- 直接stack.push(i)
- 第二种:nums2[i] = nums2[stack.peek()]
- 直接stack.push(i)
- 第三种:nums2[i] > nums2[stack.peek()]
- 那就是找到了栈顶元素的右边第一个大于该元素的值,该值为nums2[i]
- 现在就要判断一下,在nums1中是否有这个栈顶元素,通过map.containsKey(nums2[stack.peek()])
- 如果存在,就要在nums2[stack.peek()]对应的index,并在result的index下标中记录nums2[i]
- 接下来就要不断地把栈顶元素pop出来,直到栈空或者栈中的元素大于当前元素,再把当前元素push进去。保证单调栈是单调递增的。
- 第一种:nums2[i] < nums2[stack.peek()]
- result数组:
- 本题需要一个result数组(和数组一等大),一个单调栈,一个map集合。
-
代码:
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
// 需要一个数组记录结果
int[] result = new int[nums1.length];
Arrays.fill(result, -1);
// 需要一个单调栈,存放遍历过的元素
Deque<Integer> stack = new LinkedList<>();
// 需要一个map,存放数组1中的值和对应的下标
HashMap<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums1.length; i++) {
map.put(nums1[i], i);
}
// 下面是单调栈的思路,分为三种情况:
// 情况一和二是当前遍历元素小于或者等于栈顶元素,那么直接压栈
// 情况三是当前遍历元素大于栈顶元素,在nums2中找到栈顶元素右边第一个大于栈顶元素的值,然后再去nums1中看一下,是否有这个栈顶元素,如果有的话,相等于找到了nums1中元素在nums2中右边的第一个大于该元素的值,在result中记录该值即可。
stack.push(0);
for (int i = 1; i < nums2.length; i++) {
if (nums2[i] <= nums2[stack.peek()]) {
stack.push(i);
} else {
while (!stack.isEmpty() && nums2[i] > nums2[stack.peek()]) {
if (map.containsKey(nums2[stack.peek()])) {
int index = map.get(nums2[stack.peek()]);
result[index] = nums2[i];
}
stack.pop();
}
stack.push(i);
}
}
return result;
}
}