代码随想录算法训练营day11 | 232.用栈实现队列,225. 用队列实现栈,20. 有效的括号,1047. 删除字符串中的所有相邻重复项

中级软考(软件攻城狮)第3章知识点——数据结构与数据运算(线性结构+非线性结构) 本文系统梳理了数据结构中的线性与非线性结构。线性部分详细介绍了线性表(顺序/链式存储及时间复杂度对比)、(后进先出特性及应用)、队列(循环队列与双端队列)以及串(空串与子串概念)。非线性部分涵盖数组、矩阵、广义表,重点解析了树结构(二叉树性质、存储方式及遍历方法),并深入讲解了最优二叉树(哈夫曼树)的构建原理与编码应用。全文通过图示对比和实例说明,清晰呈现了各类数据结构的特点、存储方式及典型应用场景。 阅读详情

栈与队列: 

  • 栈提供push 和 pop 等等接口,所有元素必须符合先进后出规则,所以栈不提供走访功能,也不提供迭代器(iterator)。 不像是set 或者map 提供迭代器iterator来遍历所有元素。

  • 栈的底层实现可以是vector,deque,list 都是可以的, 主要就是数组和链表的底层实现。

  •  队列中先进先出的数据结构,同样不允许有遍历行为,不提供迭代器

232.用栈实现队列

  • 问题:(逻辑思路都了解,上手写就全是问题)

  • Q1: 在写constructor时,有些混乱。自己的写法是用#1 constructor

  • class MyQueue(object):
        
        # #1
        def __init__(self, stack1=[], stack2=[]):
            self.stack_in = stack1
            self.stack_out = stack2
        #2   
        # def __init__(self):
        #     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 len(self.stack_out) != 0:
                return self.stack_out.pop()
            else:
                for _ in range(len(self.stack_in)):
                    self.stack_out.append(self.stack_in.pop())
                return self.stack_out.pop()
    
        def peek(self):
            """
            :rtype: int
            """
            ans = self.pop()
            self.stack_out.append(ans)
            return ans
            
        def empty(self):
            """
            :rtype: bool
            """
            print('stack_in:',self.stack_in)
            print('stack_out:',self.stack_out)
            return len(self.stack_in) == 0 and len(self.stack_out) == 0
            
    
    
    # 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()
  • 其余的都是对的,但是提交时报错如下

  • 用这个用例来debug,结果给出如下结果
  • 在群里提问得到解答如下:from 卡哥助手-坤坤
  • “这个问题,和LeetCode的测试用例有关哈, 在初始化的时候,因为写构造函数是支持有参构造的,对于传入的stack_out不为空情况,按照展示的代码逻辑,如果传入的stack不为空,内部的定义的stack_out也会直接引用传入的非空栈,不会把传入的栈置空。所以导致,在初始化时,内部负责弹出元素的栈stack_out已经不为空了。” 
  • 如果想构造有参的构造函数,记得对传入的参数清空就行了
  • 清空操作如下:

  • 有参数和无参数构造函数的区别:
    • 需要根据实际场景来分析,在领域驱动设计中,就会避免无参构造函数,这样在后续使用该实例的过程中,当执行一些逻辑时,不用重新给涉及到的属性进行赋值。

  • Q2: 第一反应是由于有empty()函数,那么就定义变量 size。虽说不难理顺逻辑(push 就size++,pop就size--),但实际上len()对于stack的长度判断更加方便且是动态更改。
  • trick:对于pop():要判断stack_out是否为空,是因为stack_out的元素都是来自于stack_in,因此只要stack_out不为空,就说明当前队列的第一个或前几个元素都在stack_out里,这样pop()就是想要的结果;同时当stack_out不为空时,就不能向其加入新的元素,否则就会打乱顺序而出错。

  • 对于if len(self.stack_out) != 0:的判断,另一种简易写法if self.stack_out:总是需要思考一下,不习惯这样写,需要多练习。默认情况下是false,对应这里就是不为空。

  • 225. 用队列实现栈

    • 第一反应是利用from collections import deque,deque是双向的。


from collections import deque

class MyStack(object):

    def __init__(self):
        self.queue1 = deque()
        # self.queue2 = deque()
        

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

    def pop(self):
        """
        :rtype: int
        """
        return self.queue1.pop()
        

    def top(self):
        """
        :rtype: int
        """
        ans = self.pop()
        self.queue1.append(ans)
        return ans
        

    def empty(self):
        """
        :rtype: bool
        """
        return len(self.queue1) == 0
        


# 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()
  • 这样做看似简单,但是是有问题的。在实现pop()时直接使用了 self.queue1.pop(),这实际上是直接用了栈的功能,队列的pop()取到的是不一样的!这里容易犯简单的错误

  • 题解1:

    • trick: 在把除了最后一个元素都放到另一个队列之后,要把这两个队列swap。这样做是保证只有队列1存储元素,同时写法相对简单,要不然还要把队列2的所有元素重新放回队列1中。
class MyStack(object):

    def __init__(self):
        self.queue1 = deque()
        self.queue2 = deque()
        

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

    def pop(self):
        """
        :rtype: int
        """
        if self.empty():
            return None
            
        for _ in range(len(self.queue1)-1):
            self.queue2.append(self.queue1.popleft())
            
        self.queue1, self.queue2 = self.queue2, self.queue1
        return self.queue2.pop()

    '''
    def pop(self):
        """
        :rtype: int
        """
        if self.empty():
            return None
            
        for _ in range(len(self.queue1)-1):
            self.queue2.append(self.queue1.popleft())
        
        ans = self.queue1.popleft()
        for _ in range(len(self.queue2)):
            self.queue1.append(self.queue2.popleft())
        return ans
    '''


    def top(self):
        """
        :rtype: int
        """
        if self.empty():
            return None
        
        return self.queue1[-1]

    def empty(self):
        """
        :rtype: bool
        """
        return len(self.queue1) == 0
        


# 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()
  • 也可用一个队列来实现

class MyStack(object):

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

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

    def pop(self):
        """
        :rtype: int
        """
        if self.empty():
            return None
        
        for _ in range(len(self.queue)-1):
            self.queue.append(self.queue.popleft())
            
        return self.queue.popleft()
        

    def top(self):
        """
        :rtype: int
        """
        if self.empty():
            return None
        
        return self.queue[-1]
        

    def empty(self):
        """
        :rtype: bool
        """
        return len(self.queue) == 0
        


# 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()
  • 20. 有效的括号

    • 第一想法是用stack,但是写的时候没有考虑到continue来skip .append(char),否则就会出现找到了满足的情况但是还是将新的char加入到stack中。

    • 题解:

class Solution(object):
    def isValid(self, s):
        """
        :type s: str
        :rtype: bool
        """
        
        stack = []
        for char in s:
            if len(stack)!=0:
                if (char==')' and stack[-1]=='(') or (char==']' and stack[-1]=='[') or (char=='}' and stack[-1]=='{'):
                    stack.pop()
                    continue   #once one of the above conditions satisfies, then .pop(), also need to skip .append()
                
            stack.append(char)
            print(stack)
                
        return len(stack) == 0
  • 1047. 删除字符串中的所有相邻重复项

    • 这道题跟#20. 有效的括号实际上是一样的

    • 题解:

class Solution(object):
    def removeDuplicates(self, s):
        """
        :type s: str
        :rtype: str
        """
        
        stack = []
        for char in s:
            if len(stack) != 0:
                if stack[-1] == char:
                    stack.pop()
                    continue
                
            stack.append(char)
                
        return ''.join(stack)

总结:

  • 栈与队列的题目相对简单,但是小的点也不少出错。当有思路时,尽量做到考虑周全,有些时候就是写的太快然后依赖运行结果来调试,这样虽说可以ac,但是并没有记住错误的原因。

  • 用栈来实现队列和用队列实现栈需要再巩固一下

知识点:Stack implementation using lsit and collections.deque respectively

  1. Python’s built-in data structure list can be used as a stack. Instead of push(), append() is used to add elements to the top of the stack while pop() removes the element in LIFO order. Unfortunately, the list has a few shortcomings. The biggest issue is that it can run into speed issues as it grows. The items in the list are stored next to each other in memory, if the stack grows bigger than the block of memory that currently holds it, then Python needs to do some memory allocations. This can lead to some append() calls taking much longer than other ones.
  2. Python stack can be implemented using the deque class from the collections module. Deque is preferred over the list in the cases where we need quicker append and pop operations from both the ends of the container, as deque provides an O(1) time complexity for append and pop operations as compared to list which provides O(n) time complexity. 

        

代码随想录算法训练营Day11 | 232.实现队列 | 225.队列实现 | 20. 有效括号 | 1047. 删除字符串中的所有相邻重复项 | 394 使用实现队列的下列操作:push(x) – 将一个元素放入队列的尾部。pop() – 从队列首部移除元素。peek() – 返回队列首部的元素。empty() – 返回队列是否为空。说明:你只能使用标准的操作 – 也就是只有 push to top, peek/pop from top, size, 和 is empty操作是合法的。你所使用的语言也许不支持。你可以使用 list 或者 deque(双端队列)来模拟一个,只要是标准的操作即可。 阅读详情

相关推荐

代码随想录算法训练营:10/60

包含LC的四道题目,还有相应概念的补充。暂时告别了复杂的字符串处理,来到了队列的应用。这两者的特性都是一定的,常用的函数也就那几个,主要是控制怎么模拟出正确的过程。

Dustin_c的博客 754

代码随想录算法训练营11|232.实现队列225.队列实现20. 有效括号1047. 删除字符串中的所有相邻重复项

思路:需要用两个实现队列的先进先出。一个输入,一个输出,用来调整数据出的顺序。在push数据的时候,只要将数据放入输入;而在输出的时候,就需要将数据先读入输出,再弹出。弹出数据的过程,要注意判断输出是否为空。由于结构的特殊性,非常适合做对称匹配类的题目。括号匹配时使用解决的经典问题。要注意的点就是,最后返回的时候 res 的长度是 0 到 slow。还有一个双指针的版本,作为如果不让用的解决方法。(2)左右括号不对称。

Yinems的博客 320

代码随想录训练营第42期 打卡总结 - 刷题记录】

打卡总结

记得要努力变强 1605

代码随想录算法训练营 | 专题五 /队

stack overflow

m0_56867252的博客 1159

GXF 3.2.0 to 4.0 CUDA 12 路径 API 与数据结构增量分析

分析范围:以仓库中与分支对比为基础,聚焦)可用的公共 API 与数据结构变化。由于 GXF 核心头文件在各 CUDA 版本间共享,下列新增/修改的接口在 CUDA 12 构建上同样生效。对比链接:https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_nitros/compare/release-3.2…release-4.0。

eloudy的专栏 244

快速学会数据结构中的链式队列与循环队列

一种允许从一端插入数据,另外一端删除数据的线性存储结构称为队列。把数据插入的这端称为队列的队尾, 数据删除这端称为队列的队头。插入操作称为入队;删除操作称为出队。先进先出、后进后出数据缓存。

2401_82745609的博客 536

数据结构】图的应用:最小生成树(Prim / Kruskal)

摘要:最小生成树(MST)是带权连通无向图中边权总和最小的生成树,常用于网络优化问题。Prim算法从顶点出发,逐步选择连接已选和未选顶点集的最小边,适合稠密图(时间复杂度O(n²))。Kruskal算法按边权排序后依次选择不构成环的边,适合稀疏图(时间复杂度O(e log e))。两者均基于贪心策略,但Prim侧重顶点扩张,Kruskal侧重边合并。关键区别在于数据结构(Prim用优先队列,Kruskal用并查集)和适用场景。典型例题需掌握选边过程,记忆口诀为“稠密Prim,稀疏Kruskal”。软考中常考

bianyuan172的博客 319

数据结构 --- 二叉树&哈希表

本篇数据结构学习笔记分为二叉树、哈希表两大板块。二叉树部分讲解树形基础概念、链式存储方式、前 / 中 / 后序遍历算法,介绍带占位符字符串递归创建二叉树的方法,配套结点计数、深度计算、内存销毁等递归代码实现,补充二叉树核心数学性质。哈希表板块梳理哈希函数、哈希冲突概念,对比开放定址法、链地址法两种冲突解决方案,分析操作的时间复杂度。最后完整给出拉链哈希表五大功能模块的 C 语言实现代码,讲解插入、查找、打印、销毁的执行流程,同时点明现有代码的缺陷与优化方向。

2401_86288082的博客 707

数据结构:双向链表 内核链表 链式队列

本文介绍了链表操作中的几种常用算法技巧。主要包括:1. 快慢指针法(查找中间节点和倒数第k个节点);2. 链表基本操作(查找、删除特定节点、逆序、排序);3. 环形链表处理(判断是否有环、获取环入口);4. 双向链表操作(头插尾插、头删尾删);5. 内核链表与普通链表的区别;6. 队列的基本概念(FIFO特性)及其应用。这些算法涵盖了链表操作的核心技术,包括单/双向链表处理、环形链表检测以及队列实现等常见数据结构问题。

yxg0505的博客 438

数据结构】C语言实现链式二叉树

本文系统介绍了链式二叉树的实现与操作,包括节点创建、遍历算法(先序、中序、后序、层序)、节点统计(总数、叶子节点、左右子节点)、高度计算、层级节点查询、节点查找、完全二叉树判断、二叉树翻转和销毁等16个核心功能。重点阐述了递归思想在二叉树操作中的应用,并展示了队列在层序遍历和完全二叉树判断中的关键作用。所有操作均通过C语言实现,提供了完整的代码示例,为理解和实现链式二叉树数据结构提供了全面参考。

Jupiter1007的博客 326

数据结构】平衡二叉树(AVL)与哈夫曼树

本文系统讲解了AVL树和哈夫曼树两大高频考点。AVL树通过平衡因子(-1/0/1)实现自平衡,详细解析了LL、RR、LR、RL四种旋转操作及其应用场景,确保查找效率维持在O(log n)。哈夫曼树部分阐述了其构造方法(每次合并最小权值节点)和WPL计算,并给出哈夫曼编码的生成规则。文章配备典型例题和记忆口诀,强调AVL旋转与哈夫曼WPL计算是重点题型,建议重点掌握平衡因子判断与旋转操作,以及哈夫曼树的构建流程。

bianyuan172的博客 270

408 数据结构|完全二叉树两道典型题:第 6 层叶结点数与叶结点总数

除最后一层外:全部满最后一层:允许不满,但必须从左到右连续排列○/ \○ ○/ \ / \○ ○ ○ ○/ \ /○ ○ ○尽量让这一层直接成为最后一层= 39总结点数 = 2n0 - 1或总结点数 = 2n0最少 = 2n0 - 1最多 = 2n0n0 = 124最少 = 2×124 - 1 = 247最多 = 2×124 = 248。

2301_82049134的博客 154

嵌入式C语言常见考察点(2)

本文介绍了循环队列实现、 冒泡排序优化、二分查找、 位运算应用、volatile关键字重要性、大小端判断等

2301_79475128的博客 160

第 4 章 数据结构总览:SDMA 在驱动里的实体

本章将硬件概念映射到SDMA驱动的C数据结构,主要包含三层嵌套关系:芯片级amdgpu_sdma管理所有SDMA实例,实例级amdgpu_sdma_instance对应物理引擎(含GFX和Page两条队列),队列级amdgpu_ring处理具体命令。关键字段包括固件管理、队列状态、中断源、硬件差异抽象(函数指针)等,完整反映了"多实例→双队列"的硬件模型。通过这种层级化设计,驱动实现了对SDMA引擎的精细化控制。

图形/计算GPU的驱动与虚拟化技术分享园地 331

数据结构】自平衡二叉搜索树各种旋转算法原理解析及AVL树的C++实现

上一篇文章我们实现的搜索二叉树虽然平均效率还不错,但是在比较极端的情况下会退化成一条单支树,这时候原本看起来很快的查找也会变成。

qeen87的博客 321

数据结构:二叉树

树:由根节点和若干个子节点构成的具有一对多关系的数据的集合,称为树形结构。完全二叉树:在满二叉树基础上,按照从左到右,从上到下依次增加节点的树形结构。二叉树:树的广度为2的树形结构,且各节点的左右子节点不能交换。满二叉树:在不增加层数的情况下,无法再增加一个节点。树的度(数的广度):树中节点最大的度是该数的广度。K层满二叉树:第K层的节点个数:2^(K-1)叶子节点(终端节点):向后没有子节点的节点。分支节点(非终端节点):有子节点的节点。节点的度:节点的子节点个数。叶子节点的节点的度为0。

yxg0505的博客 509

数据结构】图的遍历:广度优先搜索(BFS)

摘要: 广度优先搜索(BFS)是一种基于队列实现的图遍历算法,核心思想是“层层推进”,先访问起点邻接顶点,再逐层扩展。与DFS的纵向深入不同,BFS横向扩展,适合求解无权图最短路径。算法关键点包括:入队时立即标记已访问,避免重复入队;时间复杂度邻接表为O(n+e),邻接矩阵为O(n²)。BFS生成树具有“矮胖”特性,根到任意顶点的路径为最短路径。典型应用包括连通性判断、二分图检测等。需重点掌握队列实现逻辑及与DFS的对比(如数据结构、遍历顺序等)。软考常考BFS序列模拟及陷阱(如访问标记时机)。

bianyuan172的博客 263

数据结构】二叉树的遍历:层次遍历

摘要: 层次遍历是二叉树的广度优先遍历(BFS),按从上到下、从左到右顺序访问节点,核心实现依赖队列(先进先出)。与深度优先遍历(DFS,用/递归)不同,层次遍历先处理根节点,再逐层扩展子节点,时间复杂度为O(n)。典型应用包括求树高、判断完全二叉树、图形化打印等。关键区别:DFS通过递归/实现,层次遍历通过队列实现。记忆口诀:“层次遍历用队列,根节点先入队;深度优先用递归,广度优先用队列。” 选择题常考查其与DFS的对比及队列特性。 关键词: 层次遍历、BFS、队列、二叉树、DFS

bianyuan172的博客 221
上一篇: (二刷)代码随想录算法训练营day10 | 459.重复的子字符串
下一篇: 代码随想录算法训练营day13 | 150. 逆波兰表达式求值,239. 滑动窗口最大值,347.前 K 个高频元素
jzh013
博客等级 码龄4年 7粉丝 · 48原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值