《代码随想录》学习笔记,原链接:https://programmercarl.com/
1.栈与队列基本知识
232.用栈实现队列
- 核心代码模式
class MyQueue:
def __init__(self):
self.stack_in = [] # 输入栈
self.stack_out = [] # 输出栈
def push(self, x: int) -> None:
self.stack_in.append(x) # 入栈
def pop(self) -> int:
if self.empty(): # 调用empty()函数,判断对象的输入栈和输出栈是否都为空
return None
if self.stack_out: # 判断输出栈是否为空(不能是self.stack_out.empty())
return self.stack_out.pop() # 若不为空,则直接移除stack_out尾部元素,即输出栈的开头元素
else:
for i in range(len(self.stack_in)): # 若输出栈为空,则先将输入栈的数据压倒输出栈,在移除输出栈元素,注意stack_in要加self,而且range(len(self.stack_in))不能改成self.stack_in
self.stack_out.append(self.stack_in.pop())
return self.stack_out.pop()
def peek(self) -> int:
result = self.pop() # 先调用self.pop()函数,将头部元素删除,并提取出来
self.stack_out.append(result) # 再将最后一个元素,压回栈
return result
def empty(self) -> bool:
if not (self.stack_in or self.stack_out): # 判断两个栈是否都为空,注意这里不能是and(逻辑上,应该是stack_in空 和 stack_out空,等价于非(stack_in不空 或 stack_out不空))
return True
return False
# Your MyQueue object will be instantiated and called as such:
# obj = MyQueue()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.peek()
# param_4 = obj.empty()
# param_4 = obj.empty()
225.用队列实现栈
- 核心代码模式
class MyStack:
def __init__(self):
self.queue = deque() # 构建队列,注意要加self
def push(self, x: int) -> None:
self.queue.append(x) # 将元素放入队列
def pop(self) -> int:
if self.empty(): # 判断原队列是否为空
return None
for i in range(len(self.queue) - 1): # 弹出最后一个元素,相当于把前面所有元素,出队列后重新压进队列
self.queue.append(self.queue.popleft())
return self.queue.popleft() # 调用列表的popleft()函数,获取队列第一个元素并将其删除
def top(self) -> int:
result = self.pop()
self.queue.append(result)
return result
def empty(self) -> bool:
if not self.queue: # 如果队列为空,则返回True
return True
return False
# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()
1047.删除字符串中的所有相邻重复项
- 核心代码模式
class Solution:
def removeDuplicates(self, s: str) -> str:
record = [] # 构建栈
for i in range(len(s)):
if len(record) != 0 and s[i] == record[-1]:
record.pop() # 若相邻重复则删除
else:
record.append(s[i]) # 压入栈
result = "".join(record) # 将结果拼接成字符串
return result
- ACM模式
class Solution:
def removeDuplicates(self, s: str) -> str:
record = [] # 构建栈
for i in range(len(s)):
if len(record) != 0 and s[i] == record[-1]:
record.pop() # 若相邻重复则删除
else:
record.append(s[i]) # 压入栈
result = "".join(record) # 将结果拼接成字符串
return result
# 输入字符串s
s = input("输入字符串s:")
# 删除字符串中的所有相邻重复项
solution = Solution()
result = solution.removeDuplicates(s)
print(result)
150.逆波兰表达式求值
- 核心代码模式
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
record = []
for token in tokens:
if token not in {'+', '-', '*', '/'}: # 判断当前字符是不是运算符
record.append(int(token)) # 将数字字符改为int型后压入栈
else:
num1 = record.pop()
num2 = record.pop()
if token == '+':
record.append(num1 + num2)
if token == '-':
record.append(num2 - num1) # 注意这里根据栈的先进后出,应该是(num2 - num1)
if token == '*':
record.append(num1 * num2)
if token == '/':
record.append(int(num2 / num1)) # 注意这里根据栈的先进后出,应该是(num2 / num1),并且向零截断(向零取整)常使用int()来实现
result = record.pop() # 将计算结果返回
return result
- ACM模式
class Solution:
def evalRPN(self, tokens) -> int:
record = []
for token in tokens:
if token not in {'+', '-', '*', '/'}: # 判断当前字符是不是运算符
record.append(int(token)) # 将数字字符改为int型后压入栈
else:
num1 = record.pop()
num2 = record.pop()
if token == '+':
record.append(num1 + num2)
if token == '-':
record.append(num2 - num1) # 注意这里根据栈的先进后出,应该是(num2 - num1)
if token == '*':
record.append(num1 * num2)
if token == '/':
record.append(int(num2 / num1)) # 注意这里根据栈的先进后出,应该是(num2 / num1),并且向零截断(向零取整)常使用int()来实现
result = record.pop() # 将计算结果返回
return result
# 输入字符串数组tokens
tokens = input("输入字符串数组tokens:").split(",")
# 逆波兰表达式求值
solution = Solution()
result = solution.evalRPN(tokens)
print(result)
239.滑动窗口最大值
- 核心代码模式
from collections import deque
class Solution:
def que_pop(self, value):
if self.queue and self.queue[0] == value: # 如果单调队列非空,并且要弹出的元素在单调队列队头,则弹出该元素
self.queue.popleft()
def que_push(self, value):
while self.queue and value > self.queue[-1]: # 如果单调队列非空,而且新加入的元素大于单调队列队尾元素
self.queue.pop() # 直接调用pop()函数,则将小于新加元素的值全部弹出
self.queue.append(value) # 直接调用append()函数,将新的元素加入单调队列尾部
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
self.queue = deque() # 构建可以被整个类调用的单调队列
record = [] # 记录最大值
for i in range(k): # 先将前k个数字压入队列
self.que_push(nums[i])
record.append(self.queue[0]) # 先将前k个元素中的最大值记录下来
for i in range(k, len(nums)):
self.que_pop(nums[i - k]) # 弹出第i - k个元素
self.que_push(nums[i]) # 将第i个元素加入单调队列
record.append(self.queue[0]) # 将此时的最大值保存
return record
- ACM模式
from collections import deque
class Solution:
def que_pop(self, value):
if self.queue and self.queue[0] == value: # 如果单调队列非空,并且要弹出的元素在单调队列队头,则弹出该元素
self.queue.popleft()
def que_push(self, value):
while self.queue and value > self.queue[-1]: # 如果单调队列非空,而且新加入的元素大于单调队列队尾元素
self.queue.pop() # 直接调用pop()函数,则将小于新加元素的值全部弹出
self.queue.append(value) # 直接调用append()函数,将新的元素加入单调队列尾部
def maxSlidingWindow(self, nums, k):
self.queue = deque() # 构建可以被整个类调用的单调队列
record = [] # 记录最大值
for i in range(k): # 先将前k个数字压入队列
self.que_push(nums[i])
record.append(self.queue[0]) # 先将前k个元素中的最大值记录下来
for i in range(k, len(nums)):
self.que_pop(nums[i - k]) # 弹出第i - k个元素
self.que_push(nums[i]) # 将第i个元素加入单调队列
record.append(self.queue[0]) # 将此时的最大值保存
return record
# 输入整数数组nums和整数k
nums = list(map(int, input("输入字符串数组tokens:").split(",")))
k = int(input("输入整数k:"))
print(nums)
# 滑动窗口最大值
solution = Solution()
result = solution.maxSlidingWindow(nums, k)
print(result)
347.前K个高频元素
- 核心代码模式
import heapq # 导入小堆栈库
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
record = {} # 构建哈希表字典,用于统计每个数字出现的频率
for num in nums:
record[num] = record.get(num, 0) + 1 # 添加key / 增加已有key的value
prior_queue = [] # 通过列表构建小堆栈,用于统计元素频率
for key, value in record.items(): # 记录前k个高频元素
heapq.heappush(prior_queue, (value, key)) # 将(value, key)存入小堆栈,value放在前面有利于排序
if len(prior_queue) > k:
heapq.heappop(prior_queue) # 如果存入的元素大于k个,则将value值最小的那个元素弹出
result = [0] * k # 构建一个长度为k的列表,存放元素结果
for i in range(k-1, -1, -1): # 由于是小堆栈,所以将结果倒叙存入到result中
result[i] = heapq.heappop(prior_queue)[1] # 将prior_queue中的最小值依次弹出,并存入result中,注意[1]表示存的是key
return result
- ACM模式
import heapq # 导入小堆栈库
class Solution:
def topKFrequent(self, nums, k):
record = {} # 构建哈希表字典,用于统计每个数字出现的频率
for num in nums:
record[num] = record.get(num, 0) + 1 # 添加key / 增加已有key的value
prior_queue = [] # 通过列表构建小堆栈,用于统计元素频率
for key, value in record.items(): # 记录前k个高频元素
heapq.heappush(prior_queue, (value, key)) # 将(value, key)存入小堆栈,value放在前面有利于排序
if len(prior_queue) > k:
heapq.heappop(prior_queue) # 如果存入的元素大于k个,则将value值最小的那个元素弹出
result = [0] * k # 构建一个长度为k的列表,存放元素结果
for i in range(k - 1, -1, -1): # 由于是小堆栈,所以将结果倒叙存入到result中
result[i] = heapq.heappop(prior_queue)[1] # 将prior_queue中的最小值依次弹出,并存入result中,注意[1]表示存的是key
return result
# 输入整数数组nums和整数k
nums = list(map(int, input("输入字符串数组tokens:").split(",")))
k = int(input("输入整数k:"))
print(nums)
# 前K个高频元素
solution = Solution()
result = solution.topKFrequent(nums, k)
print(result)