Leetcode刷题笔记58:单调栈1(739. 每日温度-496. 下一个更大元素 I)

107 阅读4分钟

导语

leetcode刷题笔记记录,本篇博客是贪心部分的第二期,主要记录题目包括:

知识点

单调栈

单调栈(Monotonic Stack)是一种数据结构,主要用于解决一系列元素中与大小有关的问题,如求解每个元素左侧或右侧第一个比它大或小的元素。单调栈维护了一个单调递增或单调递减的序列。

工作原理:

  1. 当一个新元素入栈时,会与栈顶元素进行比较。
  2. 如果新元素比栈顶元素大(或小,取决于是递增还是递减单调栈),则直接将新元素压入栈。
  3. 如果新元素比栈顶元素小(或大),则将栈顶元素弹出,直到栈为空或者找到一个比新元素还小(或大)的栈顶元素,然后再将新元素压入栈。

举例:

假设有一个数组 [2, 1, 5, 6, 2, 3],我们想要找到数组中每个元素右侧第一个比它大的元素。

  1. 初始化一个空栈。
  2. 遍历数组元素:
    • 当栈为空或新元素小于等于栈顶元素时,将新元素的索引压入栈。
    • 当新元素大于栈顶元素时,弹出栈顶元素,并记录该元素右侧第一个比它大的元素是当前新元素。重复这一步,直到栈为空或新元素不再大于栈顶元素,然后将新元素压入栈。

按照以上逻辑,处理 [2, 1, 5, 6, 2, 3] 后,得到每个元素右侧第一个比它大的元素如下:

  • 2 的右侧第一个比它大的元素是 5
  • 1 的右侧第一个比它大的元素是 5
  • 5 的右侧第一个比它大的元素是 6
  • 6 的右侧没有比它大的元素
  • 2 的右侧第一个比它大的元素是 3
  • 3 的右侧没有比它大的元素

这样,单调栈能在 O(n) 的时间复杂度内解决这个问题。这也是单调栈最常见的应用之一。

Leetcode 739. 每日温度

题目描述

给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。

示例 1:

输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]

示例 2:

输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]

示例 3:

输入: temperatures = [30,60,90]
输出: [1,1,0]

 

提示:

  • 1 <= temperatures.length <= 105
  • 30 <= temperatures[i] <= 100

解法

整体思路如下:

  1. 初始化一个空栈。
  2. 遍历数组元素:
    • 当栈为空或新元素小于等于栈顶元素时,将新元素的索引压入栈。
    • 当新元素大于栈顶元素时,弹出栈顶元素,并记录该元素右侧第一个比它大的元素是当前新元素。重复这一步,直到栈为空或新元素不再大于栈顶元素,然后将新元素压入栈。

示意图如下,详细过程可参考代码随想录:

image.png

class Solution:
    def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
        stack = [0]  # 初始化一个栈,存放温度的索引,初始时只有第一个元素的索引
        result = [0] * len(temperatures)  # 初始化结果列表,长度与输入列表相同,初始值都为0

        # 从第二个元素开始遍历整个列表
        for i in range(1, len(temperatures)):
            # 如果当前温度小于或等于栈顶索引对应的温度
            if temperatures[i] <= temperatures[stack[-1]]:
                # 将当前温度的索引压入栈中
                stack.append(i)
            else:
                # 如果当前温度大于栈顶索引对应的温度,则进入循环
                while len(stack) > 0 and temperatures[i] > temperatures[stack[-1]]:
                    # 弹出栈顶元素(因为找到了更高的温度)
                    last = stack.pop()
                    # 计算两个温度之间的天数,并更新结果列表
                    result[last] = i - last
                # 将当前温度的索引压入栈中(因为可能是后续温度中的“栈顶”元素)
                stack.append(i)

        return result  # 返回结果列表

Leetcode 496. 下一个更大元素 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

 

提示:

  • 1 <= nums1.length <= nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 104
  • nums1nums2中所有整数 互不相同
  • nums1 中的所有整数同样出现在 nums2 中

 

进阶: 你可以设计一个时间复杂度为 O(nums1.length + nums2.length) 的解决方案吗?

解法

class Solution:
    def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
        stack = [0]  # 初始化栈,用于存放 nums2 的索引
        result = [-1] * len(nums1)  # 初始化结果数组,长度与 nums1 相同,初始值都设为 -1
        val2index = dict()  # 创建一个字典,用于存放 nums1 中元素到其索引的映射

        # 遍历 nums1,建立元素到索引的映射
        for i in range(len(nums1)):
            val2index[nums1[i]] = i

        # 遍历 nums2,寻找“下一个更大元素”
        for i in range(1, len(nums2)):
            # 如果当前元素小于栈顶元素,将其索引入栈
            if nums2[i] < nums2[stack[-1]]:
                stack.append(i)
            else:
                # 如果当前元素大于栈顶元素,则进入循环
                while len(stack) > 0 and nums2[i] > nums2[stack[-1]]:
                    # 查看栈顶元素是否出现在 nums1 中
                    if nums2[stack[-1]] in val2index.keys():
                        # 如果出现,则更新 result 中相应位置的值
                        index = val2index[nums2[stack[-1]]]
                        result[index] = nums2[i]
                    # 弹出栈顶元素
                    stack.pop()
                # 将当前元素的索引入栈
                stack.append(i)

        return result  # 返回结果