Leetcode第二期 Task03 单调栈 496.下一个更大的元素 I 739.每日温度


一、单调栈

单调栈

简介:
单调栈(Monotone Stack):一种特殊的栈。在栈的先进后出规则基础上,要求从 栈顶 到 栈底 的元素是单调递增(或者单调递减)。其中满足从栈顶到栈底的元素是单调递增的栈,叫做单调递增栈。满足从栈顶到栈底的元素是单调递减的栈,叫做单调递减栈

1.1单调递增栈

单调递增栈:只有比栈顶元素小的元素才能直接进栈,否则需要先将栈中比当前元素小的元素出栈,再将当前元素入栈。

单调递增栈出入栈过程:

  • 假设当前进栈元素为 x,如果栈顶元素大于 x,则直接入栈。
  • 否则从栈顶开始遍历栈中元素,把小于 x 或者等于 x 的元素弹出栈,直到遇到一个大于 x 的元素为止,然后再把 x 压入栈中。

1.2单调递减栈

**单调递减栈:**只有比栈顶元素大的元素才能直接进栈,否则需要先将栈中比当前元素大的元素出栈,再将当前元素入栈。

单调递减栈出入栈过程:

  • 假设当前进栈元素为 x,如果栈顶元素小于 x,则直接入栈。
  • 否则从栈顶开始遍历栈中元素,把大于 x 或者等于 x 的元素弹出栈,直到遇到一个小于 x 的元素为止,然后再把 x 压入栈中。

1.3单调栈适用场景

单调栈可以在时间复杂度为 的情况下,求解出某个元素左边或者右边第一个比它大或者小的元素。

所以单调栈一般用于解决一下几种问题:

  • 寻找左侧第一个比当前元素大的元素
  • 寻找左侧第一个比当前元素小的元素
  • 寻找右侧第一个比当前元素大的元素
  • 寻找右侧第一个比当前元素小的元素
  1. 寻找左侧第一个比当前元素大的元素
    从左到右遍历元素,构造单调递增栈(从栈顶到栈底递增):一个元素左侧第一个比它大的元素就是将其「插入单调递增栈」时的栈顶元素。如果插入时的栈为空,则说明左侧不存在比当前元素大的元素。

  2. 寻找左侧第一个比当前元素小的元素
    从左到右遍历元素,构造单调递减栈(从栈顶到栈底递减):一个元素左侧第一个比它小的元素就是将其「插入单调递减栈」时的栈顶元素。如果插入时的栈为空,则说明左侧不存在比当前元素小的元素。

  3. 寻找右侧第一个比当前元素大的元素

    • 从左到右遍历元素,构造单调递增栈(从栈顶到栈底递增):一个元素右侧第一个比它大的元素就是将其「弹出单调递增栈」时即将插入的元素。如果该元素没有被弹出栈,则说明右侧不存在比当前元素大的元素。
    • 从右到左遍历元素,构造单调递增栈(从栈顶到栈底递增):一个元素右侧第一个比它大的元素就是将其「插入单调递增栈」时的栈顶元素。如果插入时的栈为空,则说明右侧不存在比当前元素大的元素。
  4. 寻找右侧第一个比当前元素小的元素

    • 从左到右遍历元素,构造单调递减栈(从栈顶到栈底递减):一个元素右侧第一个比它小的元素就是将其「弹出单调递减栈」时即将插入的元素。如果该元素没有被弹出栈,则说明右侧不存在比当前元素小的元素。
    • 从右到左遍历元素,构造单调递减栈(从栈顶到栈底递减):一个元素右侧第一个比它小的元素就是将其「插入单调递减栈」时的栈顶元素。如果插入时的栈为空,则说明右侧不存在比当前元素小的元素。

上边的分类解法有点绕口,可以简单记为以下条规则:

无论哪种题型,都建议从左到右遍历元素。

查找 比当前元素大的元素 就用 单调递增栈,查找 比当前元素小的元素 就用 单调递减栈。

左侧 查找就看 插入栈 时的栈顶元素,从 右侧 查找就看 弹出栈时即将插入的元素。

1.4 代码模板

单调递增栈:

def monotoneIncreasingStack(nums):
	stack = []
	for num in nums:
		while stack and num >= stack[-1]:
			stack.pop()
		stack.append(num)

单调递减栈:

def monotoneDecreasingStack(nums):
	stack = []
	for num in nums:
		while stack and num <= stack[-1]:
			stack.pop()
		stack.append(num)

二、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 。

分析:
这个题对应第三种情况,寻找右侧第一个比当前元素大的元素,因此,用单调栈进行解决即可。

代码:

class Solution:
    def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
        reslut = []
        for num1 in nums1:
            stack = []
            find = False
            for num2 in nums2:
                while stack and num2 >= stack[-1]:
                    if stack[-1] == num1:
                        reslut.append(num2)
                        find = True
                    stack.pop()
                stack.append(num2)
            if not find:
                reslut.append(-1)
        return reslut

运行结果:
在这里插入图片描述
这个用时太离谱了。发现我没用到单调栈的好处,反倒写成了暴力解法,时间复杂度 O ( N 2 ) O(N^2) O(N2)

参考作者的答案,先构造单调栈后,将每一个元素的下一个最大元素都储存在一个哈希表中,在遍历第一个数组寻找答案。

class Solution:
    def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
        res = []
        stack = []
        num_map = dict()
        for num in nums2:
            while stack and num > stack[-1]:
                num_map[stack[-1]] = num
                stack.pop()
            stack.append(num)

        for num in nums1:
            res.append(num_map.get(num, -1))
        return res

在这里插入图片描述
这样就快多了。算法时间复杂度为 O ( N ) O(N) O(N)

三、739.每日温度

题目描述:
请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。

示例:

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

分析:
可以直接将数组的索引作为元素,而温度作为判定条件来构建单调递增栈,每次进行出栈操作时,对现有栈内的元素都计算索引差值,即为等待升温的天数。
代码:

class Solution:
    def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
        n = len(temperatures)
        stack = []
        result = [0 for _ in range(n)]
        for i in range(n):
            while stack and temperatures[i] > temperatures[stack[-1]]:
                index = stack.pop()
                result[index] = i-index
            stack.append(i)
        return result

运行结果:
在这里插入图片描述
内存耗费了比较多,因此多存了个辅助数组。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值