单调栈合集402
题目
402. 移掉 K 位数字
给你一个以字符串表示的非负整数 num 和一个整数 k ,移除这个数中的 k 位数字,使得剩下的数字最小。请你以字符串形式返回这个最小的数字。
示例 1 :
输入:num = "1432219", k = 3
输出:"1219"
解释:移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219 。
示例 2 :
输入:num = "10200", k = 1
输出:"200"
解释:移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
示例 3 :
输入:num = "10", k = 2
输出:"0"
解释:从原数字移除所有的数字,剩余为空就是 0 。
提示:
1 <= k <= num.length <= 105
num 仅由若干位数字(0 - 9)组成
除了 0 本身之外,num 不含任何前导零
通过次数83,164提交次数254,311
分析
输入与输出类型:字符串
K:指的是需要去除的数字个数
返回值:字符串切片【K个数字】之后的最小值
问题转化:就是去除K个数字中,剩下数值最小的数值组合
数值组合的求取:每次都是俩俩比较,从前往后和从后往前的比较会直接影响数值的大小
Solution1
def removeKdigits(num: str, k: int) -> str:
stack = [] # 新建一个栈
remain = len(num) - k # 求最小数的位数
for digit in num:
while k and stack and stack[-1] > digit: # 单调减栈,从栈底到栈顶一次递减
stack.pop() # 指针所在位置的数字大于入栈数字,则弹出指针位置处数字
k -= 1
stack.append(digit)
return ''.join(stack[:remain]).lstrip('0') or '0' # 列表方法去掉前导零或者直接返回零
单调栈合集739
problem
739. 每日温度
请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 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
Solution1
class Solution:
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
# 将数组全部置为零
answer = [0] * len(temperatures)
stack = [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]]:
# 缘单调增栈,连续递增处减去上次入栈对应tp中的数值,差值即为相距天数
answer[stack[-1]] = i - stack[-1]
stack.pop()
stack.append(i)
return answer
"""
https://leetcode-cn.com/problems/daily-temperatures/solution/dai-ma-sui-xiang-lu-dai-ni-xue-tou-dan-d-kwbv/
https://leetcode-cn.com/problems/daily-temperatures/solution/739mei-ri-wen-du-pythondan-diao-zhan-ton-dzva/
https://leetcode-cn.com/problems/daily-temperatures/solution/739-mei-ri-wen-du-by-eill123-nu5l/
"""
单调栈合集901
problem
901. 股票价格跨度
编写一个 StockSpanner 类,它收集某些股票的每日报价,并返回该股票当日价格的跨度。
今天股票价格的跨度被定义为股票价格小于或等于今天价格的最大连续日数(从今天开始往回数,包括今天)。
例如,如果未来7天股票的价格是 [100, 80, 60, 70, 60, 75, 85],那么股票跨度将是 [1, 1, 1, 2, 1, 4, 6]。
示例:
输入:["StockSpanner","next","next","next","next","next","next","next"], [[],[100],[80],[60],[70],[60],[75],[85]]
输出:[null,1,1,1,2,1,4,6]
解释:
首先,初始化 S = StockSpanner(),然后:
S.next(100) 被调用并返回 1,
S.next(80) 被调用并返回 1,
S.next(60) 被调用并返回 1,
S.next(70) 被调用并返回 2,
S.next(60) 被调用并返回 1,
S.next(75) 被调用并返回 4,
S.next(85) 被调用并返回 6。
注意 (例如) S.next(75) 返回 4,因为截至今天的最后 4 个价格
(包括今天的价格 75) 小于或等于今天的价格。
提示:
调用 StockSpanner.next(int price) 时,将有 1 <= price <= 10^5。
每个测试用例最多可以调用 10000 次 StockSpanner.next。
在所有测试用例中,最多调用 150000 次 StockSpanner.next。
此问题的总时间限制减少了 50%。
thinking
题目要求小于等于当前的元素,逆命题是大于当前元素
Solution1
class StockSpanner:
def __init__(self):
self.stack = [] # 定义栈结构
def next(self, price: int) -> int:
weight = 1 # 既能够作为当前元素的一次计数,也可以作为计数单位
# 单调递减栈
while self.stack and self.stack[-1][0] <= price: # 入栈元素小于当前元素
weight += self.stack.pop()[1] # 没弹出一个元素,则计数器加一
self.stack.append((price, weight)) # 存储元组形式的数据元素,可以理解为二维数组
return weight
# Your StockSpanner object will be instantiated and called as such:
# obj = StockSpanner()
# param_1 = obj.next(price)
单调栈合集1081
problem
返回 s 字典序最小的子序列,该子序列包含 s 的所有不同字符,且只包含一次。
注意:该题与 316 https://leetcode.com/problems/remove-duplicate-letters/ 相同
示例 1:
输入:s = "bcabc"
输出:"abc"
示例 2:
输入:s = "cbacdcbc"
输出:"acdb"
提示:
1 <= s.length <= 1000
s 由小写英文字母组成
Solution1
class Solution:
def smallestSubsequence(self, s: str) -> str:
stack = [] # 定义栈结构
for i in range(len(s)): # 对传入参数进行遍历
if s[i] not in stack: # 遍历的元素必须是第一次出现
# 1.栈不为空;2. 栈顶元素大于被遍历的元素;3.在被遍历的元素后面还有其他元素;
while stack and stack[-1] > s[i] and s[i:].count(stack[-1]):
stack.pop()
stack.append(s[i])
return ''.join(stack)