代码随想录刷题day58|每日温度&下一个更大元素I

文章讲述了如何用单调栈算法解决两个问题:每日温度中找到之后有更高温度的天数,以及在超集中找到每个元素对应位置之后的第一个更大元素。作者通过实例详细解释了思路和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


day58学习内容

day58主要内容

  • 每日温度
  • 下一个更大元素I

声明
本文思路和文字,引用自《代码随想录》


一、每日温度

739.原题链接

1.1、思路

  1. 使用单调栈:

    • 栈的特性: 我们使用一个栈来帮助记录那些还没有找到更高温度的日子。这个栈是单调递减的,意味着栈顶的温度总是最低的。
  2. 遍历数组:

    • 从数组的第一个元素开始遍历。
    • 对于每个元素(代表当前天的温度),我们比较它与栈顶元素(栈中元素存储的是温度的索引,因此要回数组中取值)代表的温度。
  3. 温度比较:

    • 如果当前温度小于或等于栈顶元素对应的温度,我们将当前温度的索引入栈。这表示还没有找到更高的温度,需要继续等待。
    • 如果当前温度大于栈顶元素对应的温度,这表示我们找到了一个更高的温度。我们将进行以下步骤:
      • 弹出栈顶元素。
      • 计算这一天与栈顶元素代表的天数之间的差,即为栈顶元素所需等待的天数,记录在结果中。
      • 继续检查新的栈顶元素,直到找到一个栈顶元素对应的温度大于当前温度,或者栈变空。
  4. 重复上述步骤:

    • 对数组中每个元素重复上述步骤。
  5. 处理栈中剩余元素:

    • 遍历完成后,栈中可能还有一些元素。这些元素对应的天数之后没有更高的温度出现,它们对应的结果应该是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

496.原题链接

2.1、思路

给定两个数组 nums1nums2,其中 nums2nums1 的超集。对于 nums1 中的每一个元素,需要在 nums2 中找到该元素对应位置之后的第一个比它大的元素。如果不存在,则结果为 -1

  1. 哈希表存储

    • 首先,对 nums1 的元素建立一个映射,记录每个元素在 nums1 中的位置,便于最后构建结果数组。
  2. 单调栈使用

    • 使用一个单调栈来处理 nums2。栈里存储的是 nums2 的元素索引,这些索引在栈中的顺序由栈底到栈顶是对应值递减的。
    • 遍历 nums2,对于每个元素,如果它小于或等于栈顶元素的值,则直接将其索引压入栈中。
    • 如果当前元素大于栈顶元素的值,这说明我们找到了栈顶元素的“下一个更大元素”。此时,将栈顶元素弹出,并在结果映射中更新该元素的“下一个更大元素”为当前元素。重复此操作,直到当前元素不再大于新的栈顶元素或栈为空,然后将当前元素的索引压入栈中。
  3. 构建结果

    • 通过上述过程,栈中的元素会在遇到比它大的元素时被逐个弹出,并更新结果数组。最终,每当一个元素被弹出栈时,我们就确定了它的下一个更大元素。
    • 根据 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.思维导图

本文思路引用自代码随想录,感谢代码随想录作者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值