力扣刷题笔记 栈与队列及其相关题目

 《代码随想录》学习笔记,原链接:https://programmercarl.com/

1.栈与队列基本知识

232.用栈实现队列

225.用队列实现栈

1047.删除字符串中的所有相邻重复项

150.逆波兰表达式求值

239.滑动窗口最大值

347.前K个高频元素


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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值