本篇基于b站灵茶山艾府。
下面是灵神上课讲解的题目与课后作业,课后作业还有三道实在写不下去了,下次再写。
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]
class Solution:def dailyTemperatures(self, temperatures: List[int]) -> List[int]:# 1.从右到左# st = [] # 存储的是下标# ans = [0] * len(temperatures)# for i in range(len(temperatures) - 1, -1, -1):# t = temperatures[i]# while st and temperatures[st[-1]] <= t:# # 如果栈中有元素且栈口温度小于等于当前温度,则栈口的温度不可能是前面温度的答案,弹出# st.pop()# # 如果栈不为空,说明后面存在比当前温度高的温度,记录答案# if st:# ans[i] = st[-1] - i# # 当前温度进栈# st.append(i)# return ans# 2.从左到右st = [] # 栈内存储的是还没记录答案的每日温度ans = [0] * len(temperatures)for i, t in enumerate(temperatures):# 如果栈不为空且当前温度大于栈口元素,说明当前温度是栈口温度的答案while st and t > temperatures[st[-1]]:ans[st[-1]] = i - st[-1]st.pop()# 进栈st.append(i)return ans# 第一种做法相当于每轮循环都会记录当天的答案# 第二种做法相当于只有在弹出栈时才记录答案
42. 接雨水
给定 n
个非负整数表示每个宽度为 1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
class Solution:def trap(self, height: List[int]) -> int:# 横着看,当前柱子什么时候能接水?# 当后面柱子的高度超过当前柱子的高度时,就能接水了st = [] # 栈内元素单调递增s = 0for i, right_h in enumerate(height):while st and height[st[-1]] < right_h:# 如果当前柱子高度大于栈口元素高度,说明栈口元素的柱子是能接水的mid_h = height[st.pop()] # 栈口元素高度# 如果栈中没有柱子了,那水会从左边流出去,退出if not st:breakleft_h = height[st[-1]] # 左边数字的高度w = i - st[-1] - 1 # 宽度h = min(left_h, right_h) - mid_h # 高度s += w * h # 面积st.append(i)return s
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 。
class Solution:def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:idx = {x: i for i, x in enumerate(nums1)}st = []ans = [-1] * len(nums1)# 1.从左向右# for i, x in enumerate(nums2):# # 如果当前元素大于栈口元素,说明可以记录在栈口的答案了# while st and x > nums2[st[-1]]:# j = st.pop()# if nums2[j] in idx: # 如果栈口元素在nums1中# ans[idx[nums2[j]]] = x # 记录答案# st.append(i) # 元素进栈# return ans# 2.从右到左for i in range(len(nums2) - 1, -1, -1):num = nums2[i]# 如果当前元素大于等于栈口元素,说明栈口的元素永远不可能是前面元素的答案,出栈while st and num >= nums2[st[-1]]:st.pop()# 如果栈不为空,此时栈口元素大于当前元素,说明可以记录当前元素的答案了if st and num in idx:ans[idx[num]] = nums2[st[-1]]st.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]
class Solution:def nextGreaterElements(self, nums: List[int]) -> List[int]:# 循环两遍元素,确保下一个更大元素在循环搜索中发现st = []ans = [-1] * len(nums)n = len(nums)# 1. 从左向右# for i in range(n * 2):# num = nums[i % n]# while st and num > nums[st[-1]]:# j = st.pop()# ans[j] = num# st.append(i % n)# return ans# 2.从右向左for i in range(n * 2 - 1, -1, -1):num = nums[i % n]while st and num >= nums[st[-1]]:st.pop()if st:ans[i % n] = nums[st[-1]]st.append(i % n)return ans
1475. 商品折扣后的最终价格
给你一个数组 prices
,其中 prices[i]
是商店里第 i
件商品的价格。
商店里正在进行促销活动,如果你要买第 i
件商品,那么你可以得到与 prices[j]
相等的折扣,其中 j
是满足 j > i
且 prices[j] <= prices[i]
的 最小下标 ,如果没有满足条件的 j
,你将没有任何折扣。
请你返回一个数组,数组中第 i
个元素是折扣后你购买商品 i
最终需要支付的价格。
示例 1:
输入:prices = [8,4,6,2,3]
输出:[4,2,4,2,3]
解释:
商品 0 的价格为 price[0]=8 ,你将得到 prices[1]=4 的折扣,所以最终价格为 8 - 4 = 4 。
商品 1 的价格为 price[1]=4 ,你将得到 prices[3]=2 的折扣,所以最终价格为 4 - 2 = 2 。
商品 2 的价格为 price[2]=6 ,你将得到 prices[3]=2 的折扣,所以最终价格为 6 - 2 = 4 。
商品 3 和 4 都没有折扣。
示例 2:
输入:prices = [1,2,3,4,5]
输出:[1,2,3,4,5]
解释:在这个例子中,所有商品都没有折扣。
示例 3:
输入:prices = [10,1,1,6]
输出:[9,0,1,6]
class Solution:def finalPrices(self, prices: List[int]) -> List[int]:st = []ans = prices.copy()# 1.从左到右# for i, x in enumerate(prices):# while st and x <= prices[st[-1]]:# j = st.pop()# ans[j] = prices[j] - x# st.append(i)# return ans# 2.从右到左for i in range(len(prices) - 1, -1, -1):while st and prices[i] < prices[st[-1]]:st.pop()if st:ans[i] = prices[i] - prices[st[-1]]st.append(i)return ans
901. 股票价格跨度
设计一个算法收集某些股票的每日报价,并返回该股票当日价格的 跨度 。
当日股票价格的 跨度 被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,包括今天)。
- 例如,如果未来 7 天股票的价格是
[100,80,60,70,60,75,85]
,那么股票跨度将是[1,1,1,2,1,4,6]
。
实现 StockSpanner
类:
StockSpanner()
初始化类对象。int next(int price)
给出今天的股价price
,返回该股票当日价格的 跨度 。
示例:
输入:
["StockSpanner", "next", "next", "next", "next", "next", "next", "next"]
[[], [100], [80], [60], [70], [60], [75], [85]]
输出:
[null, 1, 1, 1, 2, 1, 4, 6]解释:
StockSpanner stockSpanner = new StockSpanner();
stockSpanner.next(100); // 返回 1
stockSpanner.next(80); // 返回 1
stockSpanner.next(60); // 返回 1
stockSpanner.next(70); // 返回 2
stockSpanner.next(60); // 返回 1
stockSpanner.next(75); // 返回 4 ,因为截至今天的最后 4 个股价 (包括今天的股价 75) 都小于或等于今天的股价。
stockSpanner.next(85); // 返回 6
# 往回找小于等于今天价格的连续日期,其实就是找上一个更大元素
class StockSpanner:def __init__(self):self.st = []self.prices = []def next(self, price: int) -> int:self.prices.append(price)# 1. 从左到右# 如果当前元素大于等于栈口元素,那么将栈口元素出栈# 如果当前元素小于栈口元素,那么记录当前元素的答案while self.st and price >= self.prices[self.st[-1]]:# 如果当前股票价格大于栈口元素,那么永远不可能是后面元素的答案,弹出self.st.pop()if self.st:ans = len(self.prices) - self.st[-1] - 1else:# 如果栈没元素了,说明前面的股票都大于等于当前股票ans = len(self.prices)self.st.append(len(self.prices) - 1)return ans# 2.从右到左# 如果当前元素大于栈口元素,说明栈口的元素找到答案了,记录并弹出# 如果当前元素小于等于栈口元素,则进栈# 但由于此题是每天都要返回一次答案,这种思路是只有当当前元素大于栈口元素了,才能返回栈口元素的答案# 所以此题只能按照从右到左的思路# Your StockSpanner object will be instantiated and called as such:
# obj = StockSpanner()
# param_1 = obj.next(price)
1019. 链表中的下一个更大节点
给定一个长度为 n
的链表 head
对于列表中的每个节点,查找下一个 更大节点 的值。也就是说,对于每个节点,找到它旁边的第一个节点的值,这个节点的值 严格大于 它的值。
返回一个整数数组 answer
,其中 answer[i]
是第 i
个节点( 从1开始 )的下一个更大的节点的值。如果第 i
个节点没有下一个更大的节点,设置 answer[i] = 0
。
示例 1:
输入:head = [2,1,5]
输出:[5,5,0]
示例 2:
输入:head = [2,7,4,3,5]
输出:[7,0,5,5,0]
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:def nextLargerNodes(self, head: Optional[ListNode]) -> List[int]:st = [] # 栈里面存储的是(下标,节点值)ans = []# 从左到右# 如果当前元素大于栈口元素,说明栈口的元素找到答案了,记录并弹出# 如果当前元素小于等于栈口元素,说明还没有找到答案,进栈while head:ans.append(0) # 占位while st and head.val > st[-1][1]:j, val = st.pop()ans[j] = head.valst.append((len(ans) - 1, head.val))head = head.nextreturn ans