代码随想录训练营 Day48打卡 单调栈part01 739. 每日温度 496.下一个更大元素 I 503. 下一个更大元素II

代码随想录训练营 Day48打卡 单调栈part01

一、力扣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]

本题的目标是找到一个数组中每个元素右边第一个比它大的元素的索引,并计算与当前元素的距离。使用单调栈可以有效解决这个问题,时间复杂度为O(n),因为每个元素只会被进栈和出栈一次。

单调栈的核心思路

  • 使用一个栈来记录数组中元素的索引,而不是直接记录元素本身,这样可以方便地计算索引之间的距离。
  • 栈内保持递减顺序(栈顶到栈底),因为我们在寻找右边第一个比当前元素大的值。
  • 遍历数组时,当前元素如果比栈顶元素大,说明找到了栈顶元素的右边第一个大元素,因此可以出栈并记录结果。

三种情况分析
(1)当前元素 T[i] 小于栈顶元素 T[stack[-1]]:
由于我们在寻找右边第一个更大的元素,所以此时我们只需要将当前元素的索引压入栈中即可,保持栈的递减性。
(2)当前元素 T[i] 等于栈顶元素 T[stack[-1]]:
同样地,将当前元素的索引压入栈中,因为它可能在后续的遍历中与其他元素产生相同的比较。
(3)当前元素 T[i] 大于栈顶元素 T[stack[-1]]:
这意味着栈顶元素的右边第一个更大元素已经找到了。此时,弹出栈顶元素,并将其对应的结果设置为当前索引与栈顶索引的差值。

代码实现

class Solution:
    def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
        # 初始化答案数组,全为0,表示如果没有找到更大的元素,结果为0
        answer = [0] * len(temperatures)
        # 栈中存储的是temperatures中元素的索引,而不是元素本身
        stack = []

        # 遍历温度数组
        for i in range(len(temperatures)):
            # 当栈不为空且当前元素大于栈顶元素对应的温度
            while len(stack) > 0 and temperatures[i] > temperatures[stack[-1]]:
                # 栈顶元素索引出栈
                prev_index = stack.pop()
                # 计算距离,当前索引减去栈顶索引
                answer[prev_index] = i - prev_index
            # 将当前元素索引压入栈中
            stack.append(i)

        return answer

力扣题目链接
题目文章讲解
题目视频讲解

二、力扣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] 是如上所述的 下一个更大元素
示例
输入: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 。

题目要求找到 nums1 中每个元素在 nums2 中的下一个更大元素。使用单调栈的核心思路与“每日温度”问题类似,但这里涉及两个数组和映射的操作,稍微增加了一些复杂性。

单调栈的核心思路

  • 使用单调栈来记录遍历 nums2 时遇到的元素索引,栈内保持元素的递减顺序。
  • 当遇到一个比栈顶元素大的元素时,栈顶元素的下一个更大元素就是当前遍历的元素。
  • 使用哈希表(字典)来记录 nums1 中每个元素在 nums2 中的下一个更大元素,最后生成结果。

三种情况分析:
(1)当前元素 nums2[i] 小于栈顶元素 nums2[stack[-1]]:
当前元素仍然无法确定栈顶元素的下一个更大元素,将当前元素索引入栈。
(2)当前元素 nums2[i] 等于栈顶元素 nums2[stack[-1]]:
因为要求的是下一个更大元素,等于的情况也入栈,继续等待下一个更大元素的出现。
(3)当前元素 nums2[i] 大于栈顶元素 nums2[stack[-1]]:
找到了栈顶元素的下一个更大元素,因此需要出栈,并更新 nums1 中对应元素的结果。
重复此过程,直到栈顶元素不再小于当前元素。

代码实现

class Solution:
    def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
        # 用于存放结果,初始为-1
        ans = [-1] * len(nums1)
        # 单调栈存放nums2中的索引
        stack = []
        # 创建一个哈希表用于记录nums1中的元素及其索引
        num1_index = {num: idx for idx, num in enumerate(nums1)}

        # 遍历nums2数组
        for i in range(len(nums2)):
            # 当前元素大于栈顶元素时,找到下一个更大元素
            while stack and nums2[i] > nums2[stack[-1]]:
                # 获取栈顶元素索引
                top_index = stack.pop()
                # 如果栈顶元素在nums1中存在
                if nums2[top_index] in num1_index:
                    # 找到该元素在nums1中的位置,并更新结果
                    index = num1_index[nums2[top_index]]
                    ans[index] = nums2[i]
            # 当前元素索引入栈
            stack.append(i)
        
        return ans

力扣题目链接
题目文章讲解
题目视频讲解

三、力扣503. 下一个更大元素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:
输入: nums = [1,2,3,4,3]
输出: [2,3,4,-1,4]

本题要求在一个循环数组中找到每个元素的下一个更大元素。如果不存在,则返回 -1。循环数组意味着数组的最后一个元素的下一个元素是数组的第一个元素。

单调栈的核心思路

  • 使用单调栈记录遍历元素的索引。遍历数组两次(相当于模拟数组的循环特性),这样可以确保每个元素都能找到它的下一个更大元素(如果存在)。
  • 通过 i % len(nums) 的方式,确保在第二次遍历时索引能够正确映射回数组的实际位置。
  • 栈中保持递减顺序:在遍历过程中,如果当前元素大于栈顶元素,则意味着找到了栈顶元素的下一个更大元素。

代码实现

class Solution:
    def nextGreaterElements(self, nums: List[int]) -> List[int]:
        # 初始化结果数组,默认值为-1
        dp = [-1] * len(nums)
        # 单调栈,用来存储元素的索引
        stack = []

        # 遍历数组两次,模拟循环数组
        for i in range(len(nums) * 2):
            # 取模操作确保循环访问数组
            while stack and nums[i % len(nums)] > nums[stack[-1]]:
                # 栈顶元素的下一个更大元素是当前元素
                dp[stack[-1]] = nums[i % len(nums)]
                # 弹出栈顶元素,因为已经找到了它的下一个更大元素
                stack.pop()
            # 只在第一轮遍历时将索引压入栈中
            if i < len(nums):
                stack.append(i)

        return dp

力扣题目链接
题目文章讲解
题目视频讲解

  • 11
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值