队列 vs 栈
20. 有效的括号
运用栈尾进头出的思想实现配对
当我们遇到一个左括号时,我们会期望在后续的遍历中,有一个相同类型的右括号将其闭合。由于后遇到的左括号要先闭合,因此我们可以将这个左括号放入栈顶stack.append(item)。
当我们遇到一个右括号时,我们需要将一个相同类型的左括号闭合。此时,我们可以取出栈顶的左括号stack[-1], 并判断它们是否是相同类型的括号if stack[-1]=item。
# 方法一,仅使用栈,更省空间
stack = []
for item in s:
# 左括号
if item == '(':
stack.append(')')
elif item == '[':
stack.append(']')
elif item == '{':
stack.append('}')
# 右括号
elif not stack or stack[-1] != item: # 如果不是相同的类型,或者栈中并没有左括号,那么字符串 ss 无效,返回 \text{False}False。
return False
else:
stack.pop()。# 配对成功,删除此配对,继续遍历
return True if not stack else False # 最后True应该是stack为空
# 方法二,使用字典
class Solution:
def isValid(self, s: str) -> bool:
stack = []
mapping = {
'(': ')',
'[': ']',
'{': '}'
}
for item in s:
if item in mapping.keys():
stack.append(mapping[item])
elif not stack or stack[-1] != item: # 匹配不成功或没有匹配项
return False
else: # 匹配成功
stack.pop()
return True if not stack else False
1047. 删除字符串中的所有相邻重复项
相邻重复运用队列思想,先进后出
class Solution:
def removeDuplicates(self, s: str) -> str:
stack=[]
stack.append(s[0])
for i in range(1,len(s)):
if stack and stack[-1]==s[i]:stack.pop()
else:stack.append(s[i])
return ''.join(stack)
150. 逆波兰表达式求值
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
stack=[]
for item in tokens:
if item not in {'+','-','*','/'}:stack.append(item) # 数字则入栈
else: # 符号则计算
first_num, second_num = stack.pop(), stack.pop() # 先出两个
stack.append(int(eval(f'{second_num} {item} {first_num}'))) #再进一个计算结果
return int(stack.pop())
347. 前 K 个高频元素
【法一】counter计数
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
from collections import Counter
count_dict=sorted(Counter(nums).items(),key=(lambda x:x[1]),reverse=True) # 根据次数来逆序排序,是列表中元素为元组的形式
return [x[0] for x in count_dict[:k]]
【法二】heapq求前n个最大/最小值
可以用优先级队列的思想
时间复杂度:O(nlogk)
#空间复杂度:O(n)
import heapq
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
#要统计元素出现频率
map_ = {} #nums[i]:对应出现的次数
for i in range(len(nums)):
map_[nums[i]] = map_.get(nums[i], 0) + 1
#对频率排序
#定义一个小顶堆,大小为k
pri_que = [] #小顶堆
#用固定大小为k的小顶堆,扫面所有频率的数值
for key, freq in map_.items():
heapq.heappush(pri_que, (freq, key))
if len(pri_que) > k: #如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
heapq.heappop(pri_que)
#找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒叙来输出到数组
result = [0] * k
for i in range(k-1, -1, -1):
result[i] = heapq.heappop(pri_que)[1]
return result
字符串解码
(太难了)
递归问题可以用栈来解决,从小问题剖析,先进先出
本题核心思路是在栈里面每次存储两个信息, (左括号前的字符串, 左括号前的数字), 比如abc3[def]:
stack.pop() 表示读取最后一个值并删除
stack[-1] 表示读取最后一个值
class Solution:
def decodeString(self, s: str) -> str:
stack = [] # (str, int) 记录之前的字符串和括号外的上一个数字
num = 0 # 辅助记录数字
res = "" # 实时记录当前可以提取出来的字符串
for c in s:
if c.isdigit(): # 是数字 1-
num = num * 10 + int(c) # 针对两位数,在遍历中读取两位数
elif c == "[": # [ 2-
stack.append((res, num)) # res指的是[之前的正确结果
res, num = "", 0
elif c == "]": # ] 4-
top = stack.pop()
res += top[0] + res * top[1]
else: # 是字母 3-
res += c
return res