导语
leetcode刷题笔记记录,本篇博客是贪心部分的第二期,主要记录题目包括:
知识点
单调栈
单调栈(Monotonic Stack)是一种数据结构,主要用于解决一系列元素中与大小有关的问题,如求解每个元素左侧或右侧第一个比它大或小的元素。单调栈维护了一个单调递增或单调递减的序列。
工作原理:
- 当一个新元素入栈时,会与栈顶元素进行比较。
- 如果新元素比栈顶元素大(或小,取决于是递增还是递减单调栈),则直接将新元素压入栈。
- 如果新元素比栈顶元素小(或大),则将栈顶元素弹出,直到栈为空或者找到一个比新元素还小(或大)的栈顶元素,然后再将新元素压入栈。
举例:
假设有一个数组 [2, 1, 5, 6, 2, 3],我们想要找到数组中每个元素右侧第一个比它大的元素。
- 初始化一个空栈。
- 遍历数组元素:
- 当栈为空或新元素小于等于栈顶元素时,将新元素的索引压入栈。
- 当新元素大于栈顶元素时,弹出栈顶元素,并记录该元素右侧第一个比它大的元素是当前新元素。重复这一步,直到栈为空或新元素不再大于栈顶元素,然后将新元素压入栈。
按照以上逻辑,处理 [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 <= 10530 <= temperatures[i] <= 100
解法
整体思路如下:
- 初始化一个空栈。
- 遍历数组元素:
- 当栈为空或新元素小于等于栈顶元素时,将新元素的索引压入栈。
- 当新元素大于栈顶元素时,弹出栈顶元素,并记录该元素右侧第一个比它大的元素是当前新元素。重复这一步,直到栈为空或新元素不再大于栈顶元素,然后将新元素压入栈。
示意图如下,详细过程可参考代码随想录:
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 <= 10000 <= nums1[i], nums2[i] <= 104nums1和nums2中所有整数 互不相同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 # 返回结果