代码随想录算法训练营Day10|栈与队列Part1

理论知识

概念

队列是先进先出,栈是先进后出
在这里插入图片描述

底层实现(Python)

队列:deque实现

python中collections.deque为双端队列,即可以从前端出队,也可以从后端出队。

from collections import deque

q1 = deque()
q1.append(1)
q1.append(2)
q1.append("hello")

q1.popleft()

输出

1

队列:list实现

append 和 deque 的 append 一样,从右侧推入;
pop 可以按照索引抽取,用 index=0 即可抽出最左侧(dqeue的队头)元素。

q2 = []
q2.append(1)
q2.append(2)
q2.append("hello")

q2.pop(0)

输出

1

注意: deque.popleft() 的时间复杂度是O(1),然而 list.pop(0) 的时间复杂度是O(n) ,列表越长时间复杂度越高。CPython list implementation is array-based. pop(0) removes the first item from the list and it requires to shift left len(lst) - 1 items to fill the gap.

栈:list实现

stack = []
stack.append(1)
stack.append(2)
stack.append("hello")
print(stack)
print("取一个元素:",stack.pop())
print("取一个元素:",stack.pop())
print("取一个元素:",stack.pop())

输出

[1, 2, 'hello']
取一个元素: hello
取一个元素: 2
取一个元素: 1

栈:deque实现

from collections import deque
stack = deque()
stack.append(1)
stack.append(2)
stack.append("hello")

stack.pop()

输出

'hello'

232.用栈实现队列

在这里插入图片描述

解题思路

用栈表示队列,需要设置两个栈(stack_in、stack_out),分别用于元素进、出。
在这里插入图片描述

代码演示

class MyQueue(object):

    def __init__(self):
        """
	初始化两个空列表作为栈:in主要负责push,out主要负责pop
        """
        self.stack_in = []
        self.stack_out = []
        

    def push(self, x):
        """
        :type x: int
        :rtype: None
        """
        self.stack_in.append(x)


    def pop(self):
        """
        :rtype: int
        """
        if self.empty():
            return None
        
        if self.stack_out:
            return self.stack_out.pop()
        else:
            for i in range(len(self.stack_in)):
                self.stack_out.append(self.stack_in.pop())
            #pop前需要将【入栈】中的元素【全部】塞进【出栈】
            return self.stack_out.pop()
        

    def peek(self):
        """
        :rtype: int
        """
        ans = self.pop()
        self.stack_out.append(ans) #pop后注意放回原栈
        return ans
        

    def empty(self):
        """
        :rtype: bool
        """
        return not (self.stack_in or self.stack_out)

225.用队列实现栈

在这里插入图片描述

解题思路

直接利用Python中的双端队列(collections.deque)实现栈的操作

代码演示

from collections import deque

class MyStack(object):

    def __init__(self):
        self.que = deque()

    def push(self, x):
        """
        :type x: int
        :rtype: None
        """
        self.que.append(x)
        

    def pop(self):
        """
        :rtype: int
        """
        if self.empty():
            return null
        else:
            return self.que.pop()    


    def top(self):
        """
        :rtype: int
        """
        if self.empty():
            return None
        else:
            temp = self.que.pop()
            self.que.append(temp)
            return temp
        

    def empty(self):
        """
        :rtype: bool
        """
        return not self.que

20.有效的括号

在这里插入图片描述

解题思路

括号匹配是使用栈解决的经典问题。
由于栈结构的特殊性,非常适合做对称匹配类的题目。

写代码前先分析有几种无效字符串的情况:

  1. 字符串左方向括号有多余;
  2. 左右方向括号无多余,但括号类型不匹配;
  3. 字符串右方向括号有多余。
    在这里插入图片描述

代码演示

class Solution(object):
    def isValid(self, s):
        """
        :type s: str
        :rtype: bool
        """
        stack = []
        for char in s:
            if char == "(":
                stack.append(")")
            elif char == "{":
                stack.append("}")
            elif char == "[":
                stack.append("]")
            elif not stack or stack[-1]!= char: #list[-1]表示返回列表最后一个元素
                return False
            else:
                stack.pop()
        
        return True if not stack else False

备注:Python中list切片操作

#list[起始索引:结束索引]切片时包含起始索引位置的元素,但不包含结束索引位置的元素
# 索引为 0表示第一个,1表示第二个,-1表示最后一个,-2表示倒数第二个

# list[-1]:返回最后一个数据
# list[:1]:返回0到1的数据,故返回第一个数据
# list[1:]:返回从1到0的数据,故返回第二个到最后一个的数据(不包含结束索引位置0)
# list[-1:]:返回从-1到0的数据,故返回最后一个数据
# list[:-1]:返回从0到-1的数据,故返回第一个到倒数第二个的数据(不包含结束索引位置-1)
# list[::1]:表示步长为1,步长大于0时,返回序列为原顺序;。
# list[::-1]: 表示从右往左以步长为1进行切片。步长小于0时,返回序列为倒序
# list[::2]: 表示从左往右步长为2进行切片

list = [1, 2, 3, 4, 5]
print(list[-1])  # 5
print(list[:1])  # [1]
print(list[1:])  # [2, 3, 4, 5]
print(list[-1:])  # [5]
print(list[:-1])  # [1, 2, 3, 4]
print(list[::1])  # [1, 2, 3, 4, 5]
print(list[::-1])  # [5, 4, 3, 2, 1]
print(list[::2])  # [1, 3, 5]

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

在这里插入图片描述

解题思路

将字符串放入栈(append),放入过程中判断是否有相同字母,若有则pop。
需要考虑栈为空的情况,栈为空,直接append。

代码演示

class Solution(object):
    def removeDuplicates(self, s):
        """
        :type s: str
        :rtype: str
        """
        res = list()
        for item in s:
            if res and res[-1] == item: #栈不为空,且有相邻相同字母
                res.pop()
            else:
                res.append(item)
        return "".join(res)  # 字符串拼接(list转str)
### 代码随想录算法训练营 Day20 学习内容作业 #### 动态规划专题深入探讨 动态规划是一种通过把原问题分解为相对简单的子问题的方式来求解复杂问题的方法[^1]。 #### 主要学习内容 - **背包问题系列** - 背包问题是典型的动态规划应用场景之一。这类题目通常涉及给定容量的背包以及一系列具有不同价值和重量的物品,目标是在不超过总容量的情况下最大化所选物品的价值。 - **状态转移方程构建技巧** - 构建合适的状态转移方程对于解决动态规划问题是至关重要的。这涉及到定义好dp数组(或表格),并找到从前一个状态到下一个状态之间的关系表达式[^2]。 - **优化空间复杂度方法** - 对于某些特定类型的DP问题,可以采用滚动数组等方式来减少所需的空间开销,从而提高程序效率[^3]。 #### 实战练习题解析 ##### 题目:零钱兑换 (Coin Change) 描述:给定不同面额的硬币 coins 和一个总金额 amount。编写函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 `-1`。 解决方案: ```python def coinChange(coins, amount): dp = [float('inf')] * (amount + 1) dp[0] = 0 for i in range(1, amount + 1): for coin in coins: if i >= coin and dp[i - coin] != float('inf'): dp[i] = min(dp[i], dp[i - coin] + 1) return dp[-1] if dp[-1] != float('inf') else -1 ``` 此段代码实现了基于自底向上的迭代方式解决问题,其中 `dp[i]` 表示达到金额 `i` 所需最小数量的硬币数目[^4]。 ##### 题目:完全平方数 (Perfect Squares) 描述:给出正整数 n ,找出若干个不同的 完全平方数 (比如 1, 4, 9 ...)使得它们的和等于n 。问至少需要几个这样的完全平方数? 解答思路同上一题类似,只是这里的“硬币”变成了各个可能的完全平方数值。 ```python import math def numSquares(n): square_nums = set([i*i for i in range(int(math.sqrt(n))+1)]) dp = [float('inf')] *(n+1) dp[0] = 0 for i in range(1,n+1): for sq in square_nums: if i>=sq: dp[i]=min(dp[i],dp[i-sq]+1); return dp[n]; ``` 这段代码同样运用了动态规划的思想去寻找最优解路径,并利用集合存储所有小于等于输入值的最大平方根内的平方数作为候选集[^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值