Leetcode 20. 有效的括号
讲解前:
这道题之前是做过的,核心思路就是我们明白每一个左括号和有括号对应的顺序应该是最靠后的左括号应该越先被一个右括号补齐,所以刚好符合stack的思路,我们每一次遇到一个左括号就把他加入到stack中,然后呢每次遇到一个右括号,他应该能够和stack顶端的左括号match才行
然后呢这里再多两种edge case,就是如果遇到右括号的时候,stack里面已经没左括号了,那也不行,因为那证明左右括号的数量都不一样,那肯定更别提match了,同理在最后我们也要检查stack中是否有剩余的左括号
class Solution:
def isValid(self, s: str) -> bool:
ls = []
pren_dict = {'(': ')', '[': ']', '{': '}'}
# check each symbol in the given string
for char in s:
# if it is a left, add to the stack
if char in pren_dict.keys():
ls.append(char)
else:
# if we have a right but no left in the ls, return false
if ls:
# check the right and left match or not
check = ls.pop()
if pren_dict.get(check) != char:
return False
else:
return False
# if everything matched, the stack should be empty
return not ls
讲解后:
看完了卡哥的解析之后又多了理解,然后我为了代码能少些几行就用了字典,当然只有stack也是可以解决问题的,并且更节约空间,就是会多几行 if else 并且视频中卡哥还又考虑到了如果能够匹配成功那么字符串长度最起码一定是偶数的情况,这里我就把卡哥思路的代码写在这里
class Solution:
def isValid(self, s: str) -> bool:
if len(s) % 2 != 0:
return False
stack = []
for item in s:
if item == '(':
stack.append(')')
elif item == '[':
stack.append(']')
elif item == '{':
stack.append('}')
elif not stack or stack[-1] != item:
return False
else:
stack.pop()
return not stack
Leetcode 1047: 删除字符串相邻重复项
讲解前:
这道题的难度并不高,虽然我之前没有做过但是因为心里明白今天的任务是用栈解决问题所以就自然而然的想到方法了
这道题需要删除的字母一定要是连续的并且能够左右匹配的,所以其实和括号那道题大同小异,只是这里我们不在乎其他不匹配的字母,只需要把他们保留住,同时我们要删除的部分一定要保证是连续的,例如abcba 这里,a和b就不会像 abbac 一样被删除,所以呢解决方法就是用一个stack来记录我们要保留的字符串,需要保留的字符串无非就是一直检查栈顶的字母和新遍历到的字母不一样就可以了,一样的话就证明有两个连续的出现了,这时候需要把栈顶的pop掉,这样呢还可以继续检查剩下的是否还会再出现连续的情况,就像abbac一样,b被pop掉了之后a又变成了栈顶,然后又被发现一样,再次进行pop,最后c加进来刚好就是需要保留的字符串
class Solution:
def removeDuplicates(self, s: str) -> str:
res = []
for char in s:
if not res:
res.append(char)
else:
if char == res[-1]:
res.pop()
else:
res.append(char)
return ''.join(res)
讲解后:
卡哥的解题思路和我的一样,不过在文章中还有一个比价有意思的扩展的解法,就是利用双指针来做,快指针用来遍历整个字符串,慢指针用来记录我们要保留的字符串,在每一个循环中,我们都让快指针指向的字母等于慢指针,如果慢指针没有遇到当前所指向的字母和[slow - 1]的一样的话,就正常和快指针一样每次都increment,但是一旦遇到这种情况,慢指针需要向后退一步用来模拟栈中pop了的操作,然后呢快指针还是继续找,如果又找到了,就像abba这种情况,慢指针退到index 1了之后,快指针又指向了a,这时候慢指针还要再退到index 0,相当于要返回的字符串中目前没有元素了,abba都被删除掉了
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])
Leetcode 150. 逆波兰表达式
讲解前:
这道题虽然是一道中等难度的题,但是我觉得思路其实不难想出,也许只是代码实现的过程中需要注意一些小细节,我们无非就是在token是数字的时候就加入栈,是运算符的话就从栈顶拿两个数字进行相应的运算然后把结果放回栈顶
class Solution:
def evalRPN(self, tokens: List[str]) -> int:
num = []
for token in tokens:
if (token[0] == '-' and len(token) > 1) or token.isdigit():
num.append(int(token))
else:
num1 = num.pop()
num2 = num.pop()
if token == '+':
num.append(num2 + num1)
elif token == '-':
num.append(num2 - num1)
elif token == '*':
num.append(num2 * num1)
else:
if (num1 < 0) != (num2 < 0):
num.append(-(abs(num2) // abs(num1)))
else:
num.append(num2 // num1)
return num[0]
麻烦的点就是在除法运算中,为了保证永远向0截断,我们需要判断num1和num2是否一正一负,如果是的话,我们运算的时候可以先用他们的绝对值相除,然后再加-号
讲解后:
看完了卡哥的讲解之后思路都是一样的,然后我的解法其实应该在if 中先判断operator的,这样还不用写那么那么麻烦的表达式来确定添加正数和负数到栈里,然后呢卡哥讲到的逆波兰表达式的本质就是把中缀表达式表现成一个二叉树之后呢再用后序遍历的方法写出来