代码随想录栈与队列part02|20.有效的括号、1047. 删除字符串中的所有相邻重复项、150. 逆波兰表达式求值
20.有效的括号
思路
:
用栈解决的经典题目;
不匹配的场景就三个:
遇到左括号,把右括号加入栈;
遇到右括号,弹出栈中的元素,比较两个右括号是否一样
【若不匹配,说明字符串无效,情况2】
【若字符串还没遍历完,栈为空,说明字符串无效,情况3】
遍历完后,如果栈中还存有元素(栈不为空)【说明不匹配,字符串无效,情况1】
剪枝策略:
本题存在的一种情况:若字符串匹配,字符串长度一定是偶数
如果字符串是奇数的话,一定存在不匹配的括号
伪代码c++
:
注意: 判断时是top,之后是pop
stack<char> st;
if(s.size%2 != 0) return false
for(int i=0; i<s.size(); i++){
if(s[i]=='(') st.push(')')
else if(s[i]=='{') st.push('}')
else if(s[i]=='[]) st.push(']')
else if(! st.empty() && st.top() != s[i])
return false;
else st.pop()
}
return st.empty(); //处理第一种情况
python代码
:
# 第一次的实现代码
class Solution:
def isValid(self, s: str) -> bool:
dic = {'(':')', '[':']', '{': '}', '?':'?'}
stack = ['?']
for c in s:
if c in dic: stack.append(c)
elif dic[stack.pop()] != c: return False
return len(stack) == 1
# 代码随想录代码
class Solution:
def isValid(self, s: str) -> bool:
if len(s) % 2 != 0:
return False
stack = []
for c in s:
if c == '(':
stack.append(')')
elif c == '{':
stack.append('}')
elif c == '[':
stack.append(']')
elif not stack or stack[-1] != c:
return False
else:
stack.pop()
return True if not stack else False
# 方法二,使用字典
class Solution:
def isValid(self, s: str) -> bool:
stack = []
mapping = {
'(': ')',
'[': ']',
'{': '}'
}
for item in s:
if item in mapping.keys():
stack.append(mapping[item])
elif not stack or stack[-1] != item:
return False
else:
stack.pop()
return True if not stack else False
1047. 删除字符串中的所有相邻重复项
思路
:
该题很多人可能不会想到用栈来解决,该题难点在于删除完目前存在的重复项之后可能会出现新的重复项,类似消消乐游戏。
没有必要真的用一个栈,可以使用一个字符串去模拟栈的行为,
注意:将字符串的尾部作为栈的出口,头部作为栈的顶部
栈特别适合做相邻的一些判断,比如相邻字母,相邻括号匹配、消除
python代码
:
class Solution:
def removeDuplicates(self, s: str) -> str:
result = list()
for c in s:
if not result or c != result[-1]: # 把result写出s,调试半天orz
# 如果栈为空或者该元素与栈顶元素不同,直接将要遍历的元素放入即可
result.append(c)
else:
result.pop()
return "".join(result)
# 方法二,使用双指针模拟栈,如果不让用栈可以作为备选方法。
class Solution:
def removeDuplicates(self, s: str) -> str:
res = list(s)
slow = fast = 0
length = len(res)
while fast < length:
# 如果一样直接换,不一样会把后面的填在slow的位置
res[slow] = res[fast]
# 如果发现和前一个一样,就退一格指针
if slow > 0 and res[slow] == res[slow - 1]:
slow -= 1
else:
slow += 1
fast += 1
return ''.join(res[0: slow])
150. 逆波兰表达式求值
思路
:
逆波兰表达式-> 后缀表达式(二叉树的后序遍历)
如何用栈实现:
- 遇见数字就加入栈
- 遇见操作符就将前两个元素取出,进行运算后再加入栈
整个后缀表达式的结果就是栈的最后唯一一个元素
6//132 结果为 0
6//-132 结果为 -1
python负数整除原则
在Python中,负数整除(//)遵循以下原则:
结果向下取整到最近的整数。
如果除数和被除数都是负数,结果为正。
如果除数和被除数中至少有一个是负数,结果为负。
例如:
-7 // 2 # 结果为 -4
-7 // -2 # 结果为 3
7 // -2 # 结果为 -4
结果总是向下取整到最近的整数,即不大于真实结果的最大整数。如果结果是0,则保留0的符号。
python代码
:
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
result = list()
for t in tokens:
if t == '+' or t == '-' or t == '*' or t == '/':
nums1 = result[-1]
result.pop()
nums2 = result[-1]
result.pop()
if t == '+':
result.append(nums1+nums2)
elif t== '-':
result.append(nums2-nums1)
elif t== '*':
result.append(nums1*nums2)
else:
if nums1*nums2<0: # 两者有一个<0
result.append((abs(nums2)//abs(nums1))*(-1))
else:
result.append(nums2//nums1)
else:
result.append(int(t))
return result[-1]
随想录代码
from operator import add, sub, mul
class Solution:
op_map = {'+': add, '-': sub, '*': mul, '/': lambda x, y: int(x / y)}
def evalRPN(self, tokens: List[str]) -> int:
stack = []
for token in tokens:
if token not in {'+', '-', '*', '/'}:
stack.append(int(token))
else:
op2 = stack.pop()
op1 = stack.pop()
stack.append(self.op_map[token](op1, op2)) # 第一个出来的在运算符后面
return stack.pop()
# 2
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
stack = []
for item in tokens:
if item not in {"+", "-", "*", "/"}:
stack.append(item)
else:
first_num, second_num = stack.pop(), stack.pop()
stack.append(
int(eval(f'{second_num} {item} {first_num}')) # 第一个出来的在运算符后面
)
return int(stack.pop()) # 如果一开始只有一个数,那么会是字符串形式的