1.1栈与队列基础知识
在Python语言中,栈(Stack)和队列(Queue)是两种常用的数据结构,它们在算法和程序设计中扮演着重要的角色。
1.1.1栈(Stack)
栈是一种后进先出(Last In First Out, LIFO)的数据结构。在栈中,最后插入的元素将是第一个被删除的元素。
1.1.2栈的基本操作:
- push(x):将元素x添加到栈顶。
- pop():移除并返回栈顶元素。
- peek() 或 top():返回栈顶元素,但不移除它。
- isEmpty():检查栈是否为空。
- size():返回栈中的元素数量。
1.2.1队列(Queue)
队列是一种先进先出(First In First Out, FIFO)的数据结构。在队列中,最先插入的元素将是第一个被删除的元素。
1.2.2队列的基本操作:
- enqueue(x):将元素x添加到队尾。
- dequeue():移除并返回队头元素。
- front():返回队头元素,但不移除它。
- isEmpty():检查队列是否为空。
- size():返回队列中的元素数量。
2.1有效的括号
在编程中,检查字符串中的括号是否有效是一个常见的问题,特别是在处理表达式、代码或者数据结构时。有效的括号意味着每个开括号都有一个对应的闭括号,并且括号的顺序正确。
2.1.1问题定义
给定一个字符串,包含以下字符:'('
, ')'
, '{'
, '}'
, '['
, ']'
你需要判断这个字符串是否有效。
2.1.2有效性的条件
- 每个
'('
必须有一个对应的')'
。 - 每个
'{'
必须有一个对应的'}'
。 - 每个
'['
必须有一个对应的']'
。 - 任何时候,闭括号的数量不能超过开括号的数量。
- 括号必须正确嵌套。
2.2.1相关练习
LeetCode20
有效括号的问题,即判断一个字符串中的括号是否有效。
3.1栈来实现队列
使用栈来实现队列的功能是一种常见的数据结构问题,因为栈是后进先出(LIFO)的数据结构,而队列是先进先出(FIFO)的数据结构。要使用两个栈实现队列,我们可以利用栈的压栈和弹栈操作来模拟队列的入队和出队操作。
3.1.1基本思路
- 入队操作(enqueue):将元素压入第一个栈(我们称之为栈A)。
- 出队操作(dequeue):如果第二个栈(我们称之为栈B)为空,则将栈A的所有元素弹出并压入栈B。这样,栈A的底部元素(即队列的前端元素)将被移到栈B的顶部,然后从栈B弹出顶部元素,实现出队。
3.2.1相关练习
LeetCode232题
4.1 作业(9.10)
LeetCode225题 “用队列实现栈”
这个题目要求使用队列来实现栈的所有操作:push、pop、peek 和 empty。
5.1 删除字符串中的所有相邻重复项
我们遍历字符串中的每个字符,使用一个栈来存储不重复的字符。当我们遇到一个字符时,如果它与栈顶的字符相同,我们就从栈中移除栈顶的字符。如果它与栈顶的字符不同,我们就将它压入栈中。最后,栈中剩余的字符就是没有相邻重复项的字符序列。
这种方法的时间复杂度是O(n),其中n是字符串的长度,因为每个字符最多被压入和弹出栈一次。空间复杂度是O(n),最坏情况下,所有字符都是不同的,需要全部压入栈中。
5.1.1练习 LeetCode1047
“删除字符串中的所有相邻重复项”
这个问题可以通过使用栈来解决,具体思路是遍历字符串,对于每个字符,如果它与栈顶的字符相同,则弹出栈顶字符;如果不同,则将其压入栈中。最后,栈中的字符序列就是没有相邻重复项的字符串。
6.1 逆波兰表达式求值
逆波兰表达式求值(Reverse Polish notation,RPN,或逆波兰记法),是一种是由波兰数学家扬·武卡谢维奇1920年引入的数学表达式形式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。
6.1.1逆波兰表达式的特点
- 运算符放在它所操作的两个数的后面。
- 不需要括号来表示操作顺序,因为运算符的顺序决定了操作的顺序。
- 每个操作数和运算符都是单独的元素。
6.1.2举例
- 中缀表达式:
3 + 4 * 2
- 逆波兰表达式:
3 4 2 * +
6.1.3计算逆波兰表达式
计算逆波兰表达式通常使用栈(Stack)。算法步骤如下:
- 初始化一个空栈。
- 从左到右扫描表达式中的每个元素。
- 如果元素是操作数,将其压入栈中。
- 如果元素是运算符,从栈中弹出所需数量的操作数(根据运算符的操作数要求),执行运算,然后将结果压入栈中。
- 重复步骤2-4,直到表达式的所有元素都被扫描完毕。
- 栈中剩下的最后一个元素就是表达式的结果。
6.1.4相关练习 LeetCode150
根据逆波兰表示法(后缀表达式)计算表达式的值。逆波兰表达式是一种不需要括号,并且运算符位于操作数之后的方式来表示算术表达式的方法。
解题思路是使用一个栈来存储操作数,遍历表达式中的每个元素:
- 遇到数字时,将其压入栈中;
- 遇到运算符时,从栈中弹出两个操作数,先弹出的为右操作数,后弹出的为左操作数,然后进行相应的运算,并将结果压回栈中。
重复这个过程,直到表达式中的所有元素都被处理完毕,此时栈中只剩下一个元素,即为表达式的计算结果。