学习目标:
通过LeetCode编程练习,坚持21天每日一题,提高编程水平。
学习内容:
题目内容:
给你一个由若干括号和字母组成的字符串 s
,删除最小数量的无效括号,使得输入的字符串有效。
返回所有可能的结果。答案可以按 任意顺序 返回。
运用思想:
①回溯算法思想
回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
个人理解跟深度优先搜索算法类似,在本题中,可先利用括号匹配的规则求出字符串s中最少需要去掉的左括号数lremove和右括号数rremove,然后逐步去掉lremove个左括号和rremove个右括号,同时检测字符串是否符合规则,如何符合规则则输出为可能的结果。我们利用回溯算法来尝试搜索所有可能的结果。
②剪枝操作
回溯算法通常伴随着剪枝操作,这道题的剪枝操作通过去掉一些不符合题意和规则的搜索操作,提高算法的效率。代码中有详细步骤。
学习产出:
class Solution:
def removeInvalidParentheses(self, s: str) -> List[str]:
res = []
# lremove,rremove记录剩下要删除的左右括号个数。
lremove, rremove = 0, 0
for c in s:
if c == '(':
lremove += 1
elif c == ')':
if lremove == 0:
rremove += 1
else:
lremove -= 1
#下面这个函数能判断字符串中的括号是否正确匹配,即左右括号按顺序排列,且数目相同。
def isValid(str):
cnt = 0
for c in str:
if c == '(':
cnt += 1
elif c == ')':
cnt -= 1
if cnt < 0:
return False
return True #true
def remove(s, start, lcount, rcount, lremove, rremove):
# remove操作递归退出条件:剩下要删除的括号数为0且字符串符合正确性。
if lremove == 0 and rremove == 0:
if isValid(s):
res.append(s)
return
for i in range(start, len(s)):
#去重操作,
if i > start and s[i] == s[i - 1]:
if s[i] == '(':
lcount += 1
elif s[i] == ')':
rcount += 1
continue
#回溯条件①:剩余的字符数目小于要删除的括号个数,直接返回。
if lremove + rremove > len(s) - i:
break
#去掉左括号操作
if lremove > 0 and s[i] == '(':
remove(s[:i] + s[i+1:], i, lcount, rcount, lremove - 1, rremove);
#去掉右括号操作
if rremove > 0 and s[i] == ')':
remove(s[:i] + s[i+1:], i, lcount, rcount, lremove, rremove - 1);
#记录字符串中已有的括号数量
if s[i] == '(':
lcount += 1
elif s[i] == ')':
rcount += 1
#回溯条件②:当前右括号数量大于左括号数量,表示非法,直接返回。
if rcount > lcount:
break
remove(s, 0, 0, 0, lremove, rremove)
return res