思路:
由于栈结构的特殊性,非常适合做对称匹配类的题目。
首先要弄清楚,字符串里的括号不匹配有几种情况:
1.第一种情况,字符串里左方向的括号多余了 ,所以不匹配。
2.第二种情况,括号没有多余,但是 括号的类型没有匹配上。
3.第三种情况,字符串里右方向的括号多余了,所以不匹配。
第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false
第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符。所以return false
第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false
那么什么时候说明左括号和右括号全都匹配了呢,就是字符串遍历完之后,栈是空的,就说明全都匹配了。
代码:
class Solution:
def isValid(self, s: str) -> bool:
stack=[] # 定义一个栈
if len(s)%2==1: # 剪枝,如果字符串长度为奇数,直接返回False
return False
for i in s:
if i=='(': # 如果遇到左括号,就把对应的右括号添加到栈中
stack.append(')')
elif i == '[':
stack.append(']')
elif i == '{':
stack.append('}')
elif not stack: # 遇到右括号,如果栈为空,说明右括号没有对应的左括号,返回False
return False
elif stack[-1] != i: # 遇到右括号,如果栈顶元素不等于当前遍历的括号,返回False
return False
else: # 遇到右括号,如果栈顶元素等于当前遍历的括号,弹出栈顶元素
stack.pop()
if stack: # 遍历完字符串,如果栈不为空返回False,说明有左括号没有对应的右括号
return False
else:
return True
- 时间复杂度: O(n)
- 空间复杂度: O(n)
思路:
本题要删除相邻相同元素,相对于20. 有效的括号来说其实也是匹配问题,20. 有效的括号是匹配左右括号,本题是匹配相邻元素,最后都是做消除的操作。
本题也是用栈来解决的经典题目。
我们在删除相邻重复项的时候,其实就是要知道当前遍历的这个元素,我们在前一位是不是遍历过一样数值的元素,那么如何记录前面遍历过的元素呢?
所以就是用栈来存放,那么栈的目的,就是存放遍历过的元素,当遍历当前的这个元素的时候,去栈里看一下我们是不是遍历过相同数值的相邻元素。然后再去做对应的消除操作。
代码:
class Solution:
def removeDuplicates(self, s: str) -> str:
stack=[]
for i in s:
if stack and i==stack[-1]:
stack.pop()
else:
stack.append(i)
return "".join(stack)
- 时间复杂度: O(n)
- 空间复杂度: O(n)
逆波兰表达式概念:
我们日常的运算表达式通常是如下形式,这种成为中缀表达式,也就是运算符在运算数的中间。这种表达式人类很容易识别,并根据其进行计算,但计算机识别这种表达式非常困难。
a + b * (c - d) + e/f
因此,1920年,波兰科学家扬·武卡谢维奇(Jan ukasiewicz)发明了一种不需要括号的计算表达式的表示法将操作符号写在操作数之前,也就是前缀表达式,即波兰式(Polish Notation, PN)。上述中缀表达式转换为波兰表达式的格式如下:
+a+*b-cd/ef
从上面表达式可以看出,运算符在2个运算数的前面,因此波兰表达式也称为前缀表达式。为了便于理解,我们给出一个具体的实例,这个实例将上面的字母换成具体的数字(1 + 2 * (4 - 3) + 6/2),这个结果很容易看出来,也就是1+2*1+3 = 6。然后我们看一下波兰表达式的表示形式及运算过程。
+1+*2-4 3/ 6 2 // 从右向左扫描,当遇到运算符时计算其最近的右侧2个运算数
+1+*2-4 3 3 // 先计算最右侧的数据,也就是 6/2=3
+1+*2 1 3 // 同理,4-3 = 1
+1+2 3 // 同理,2*1= 2
+1+5
6
波兰表达式也成为前缀表达式,而逆波兰表达式则成为后缀表达式,对比可以猜出来运算符在运算数后面的表达式就是逆波兰表达式。上述表达式如果采用逆波兰表达式则如下:
1 2 4 3 -*+ 6 2 / + // 计算方式正好相反,也就是从左向右扫描
1 2 1 *+ 6 2 / +
1 2 + 6 2 / +
3 6 2 / +
3 3 +
6
思路:
其实逆波兰表达式相当于是二叉树中的后序遍历。 大家可以把运算符作为中间节点,按照后序遍历的规则画出一个二叉树。但我们没有必要从二叉树的角度去解决这个问题,只要知道逆波兰表达式是用后序遍历的方式把二叉树序列化了,就可以了。
在进一步看,本题中每一个子表达式要得出一个结果,然后拿这个结果再进行运算,那么这岂不就是一个相邻字符串消除的过程,和1047.删除字符串中的所有相邻重复项 中的对对碰游戏是不是就非常像了。只不过本题不要相邻元素做消除了,而是做运算!
代码:
版本一
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
stack=[]
for i in tokens:
if i == "+":
num1=stack.pop()
num2=stack.pop()
stack.append(int(num2+num1))
elif i == "-":
num1=stack.pop()
num2=stack.pop()
stack.append(int(num2-num1))
elif i == "*":
num1=stack.pop()
num2=stack.pop()
stack.append(int(num2*num1))
elif i == "/":
num1=stack.pop()
num2=stack.pop()
stack.append(int(num2/num1))
else:
stack.append(int(i))
return int(stack.pop())
- 时间复杂度: O(n)
- 空间复杂度: O(n)
版本二(使用eval()函数)
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
stack=[]
for i in tokens:
if i in ["+","-","*","/"]:
num1=stack.pop()
num2=stack.pop()
stack.append(int(eval(f'{num2} {i} {num1}')))
else:
stack.append(int(i))
return int(stack.pop())
补充:
eval是Python的一个内置函数,功能十分强大,这个函数的作用是,返回传入字符串的表达式的结果。就是说:将字符串当成有效的表达式来求值并返回计算结果。(就是去掉"")
eval函数实现list、dict、tuple与str之间的转化,同样str函数把list,dict,tuple转为为字符串
a = 1
b = 2
c = eval("a+b")
print(c)
#输出为3