day58学习内容
day58主要内容
- 每日温度
- 下一个更大元素I
声明
本文思路和文字,引用自《代码随想录》
一、每日温度
1.1、思路
-
使用单调栈:
- 栈的特性: 我们使用一个栈来帮助记录那些还没有找到更高温度的日子。这个栈是单调递减的,意味着栈顶的温度总是最低的。
-
遍历数组:
- 从数组的第一个元素开始遍历。
- 对于每个元素(代表当前天的温度),我们比较它与栈顶元素(栈中元素存储的是温度的索引,因此要回数组中取值)代表的温度。
-
温度比较:
- 如果当前温度小于或等于栈顶元素对应的温度,我们将当前温度的索引入栈。这表示还没有找到更高的温度,需要继续等待。
- 如果当前温度大于栈顶元素对应的温度,这表示我们找到了一个更高的温度。我们将进行以下步骤:
- 弹出栈顶元素。
- 计算这一天与栈顶元素代表的天数之间的差,即为栈顶元素所需等待的天数,记录在结果中。
- 继续检查新的栈顶元素,直到找到一个栈顶元素对应的温度大于当前温度,或者栈变空。
-
重复上述步骤:
- 对数组中每个元素重复上述步骤。
-
处理栈中剩余元素:
- 遍历完成后,栈中可能还有一些元素。这些元素对应的天数之后没有更高的温度出现,它们对应的结果应该是0(通常这在初始化结果数组时已经默认设置)。
1.2、代码
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
// 获取温度数组的长度
int lens = temperatures.length;
// 初始化结果数组,用于存储每天后需要等待多少天才有更高的温度
int[] res = new int[lens];
// 创建一个双端队列作为栈使用,存储数组索引
Deque<Integer> stack = new LinkedList<>();
// 先将第一天的索引入栈
stack.push(0);
// 从第二天开始遍历温度数组
for (int i = 1; i < lens; i++) {
// 检查当前天的温度是否小于或等于栈顶天的温度
if (temperatures[i] <= temperatures[stack.peek()]) {
// 如果是,将当前天的索引入栈,因为还没找到更高温度
stack.push(i);
} else {
// 如果当前天的温度大于栈顶天的温度
while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) {
// 计算等待天数,当前天索引减去栈顶天的索引
res[stack.peek()] = i - stack.peek();
// 栈顶元素出栈,因为已找到更高的温度
stack.pop();
}
// 将当前天的索引入栈,因为可能需要比较后续的天气
stack.push(i);
}
}
// 栈中剩余的索引代表的天数将不会有更高的温度,其结果数组中默认为0
return res;
}
}
二、下一个更大元素I
2.1、思路
给定两个数组 nums1
和 nums2
,其中 nums2
是 nums1
的超集。对于 nums1
中的每一个元素,需要在 nums2
中找到该元素对应位置之后的第一个比它大的元素。如果不存在,则结果为 -1
。
-
哈希表存储:
- 首先,对
nums1
的元素建立一个映射,记录每个元素在nums1
中的位置,便于最后构建结果数组。
- 首先,对
-
单调栈使用:
- 使用一个单调栈来处理
nums2
。栈里存储的是nums2
的元素索引,这些索引在栈中的顺序由栈底到栈顶是对应值递减的。 - 遍历
nums2
,对于每个元素,如果它小于或等于栈顶元素的值,则直接将其索引压入栈中。 - 如果当前元素大于栈顶元素的值,这说明我们找到了栈顶元素的“下一个更大元素”。此时,将栈顶元素弹出,并在结果映射中更新该元素的“下一个更大元素”为当前元素。重复此操作,直到当前元素不再大于新的栈顶元素或栈为空,然后将当前元素的索引压入栈中。
- 使用一个单调栈来处理
-
构建结果:
- 通过上述过程,栈中的元素会在遇到比它大的元素时被逐个弹出,并更新结果数组。最终,每当一个元素被弹出栈时,我们就确定了它的下一个更大元素。
- 根据
nums1
中元素的原始索引位置,从结果映射中取出答案填充到最终输出的结果数组中。
2.2、代码
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
// 创建一个栈来保存数组元素的索引
Stack<Integer> temp = new Stack<>();
// 初始化结果数组,所有元素默认值为-1(代表没有找到下一个更大的元素)
int[] res = new int[nums1.length];
Arrays.fill(res, -1);
// 创建一个哈希表来记录nums1中每个元素的索引,便于后续快速查找
HashMap<Integer, Integer> hashMap = new HashMap<>();
for (int i = 0; i < nums1.length; i++) {
hashMap.put(nums1[i], i);
}
// 将nums2的第一个元素的索引入栈
temp.add(0);
// 遍历nums2中的所有元素
for (int i = 1; i < nums2.length; i++) {
// 如果当前元素小于等于栈顶元素,将其索引入栈
if (nums2[i] <= nums2[temp.peek()]) {
temp.add(i);
} else {
// 否则,循环判断栈顶元素与当前元素的大小
while (!temp.isEmpty() && nums2[temp.peek()] < nums2[i]) {
// 如果栈顶元素小于当前元素,弹出栈顶元素
if (hashMap.containsKey(nums2[temp.peek()])) {
// 检查弹出的栈顶元素是否存在于nums1中
Integer index = hashMap.get(nums2[temp.peek()]);
// 更新nums1中对应元素的结果为当前元素(下一个更大元素)
res[index] = nums2[i];
}
temp.pop();
}
// 将当前元素索引入栈
temp.add(i);
}
}
// 返回结果数组
return res;
}
}
总结
1.感想
- 单调栈第一天,冲
- 单调栈具体的模拟过程,卡尔的视频讲的很清楚。建议去看视频,这里不画图了,太复杂了。
2.思维导图
本文思路引用自代码随想录,感谢代码随想录作者。