leetcaod22-括号生成:
正确的思考思路应该是这样的:(暴力解法)
- 生成所有的序列
- 检查是否有效
- 模式识别:子问题和原问题具有相同的结构,考虑至上而下的递归
然后通过判断优化解题方法:(回溯)
暴力解法中直到序列生成完才进行相应的筛选,其中已经生成了很多无序的序列,现在考虑在生成过程中确保每一步都能产生有序序列,利用回溯搜索其他可能的解答。
1.
这点有一题解写的非常好,摘录在这里
https://leetcode.cn/problems/generate-parentheses/solution/zui-jian-dan-yi-dong-de-dong-tai-gui-hua-bu-lun-da/
根据题解的思路自己也手动模拟一个这个实现的过程,十分标准的二叉树的回溯过程,其中上面的一张是不管其他条件,生成的类似于全排列的序列,下面的是看考虑剪枝的一个过程:右边的括号数量大于左边的时候就需要剪枝(可以去除很多无用的答案),所以这题既是要有思路,同时对于回溯算法的具体还要熟悉,实际的要求并不算低,还是很考验能力水平的。自己既然做这道题就把相应的每个细节都要考虑到。
先把最基本的实现所有组合实现出来,然后再去改进这个过程
# 本质上是一个树的深度优先搜索(前序遍历:首先收集左孩子,然后走到底,到了叶子节点再回头收拾右子节点)
from typing import List
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
if n <=0:
return []
res=[]
def dfs(paths):
# 括号是成队出现的
if len(paths)==n*2:
res.append(paths)
return
dfs(paths+'(')
dfs(paths+')')
dfs('')
return res
if __name__=='__main__':
ans=Solution().generateParenthesis(2)
print(ans)
# 打印结果如下:
['((((', '((()', '(()(', '(())', '()((', '()()', '())(', '()))', ')(((', ')(()', ')()(', ')())', '))((', '))()', ')))(', '))))']
在上面的基础上,将一些不用的结果进行去除:限制左括号与右括号的数量,增加left与right参数,分别代表左括号与右括号的数量,每生成一个就增加一个
其中不是有效的情况是:右边的括号数量大于左边的括号数量
from typing import List
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
if n <=0:
return []
res=[]
def dfs(paths,left,right):
# 限制左括号的数量不超过n,右括号的数量不超过左括号的数量
if left>n or right >left:
return
# 括号是成队出现的
if len(paths)==n*2:
res.append(paths)
return
dfs(paths+'(',left+1,right)
dfs(paths+')',left,right+1)
dfs('',0,0)
return res
if __name__=='__main__':
ans=Solution().generateParenthesis(2)
print(ans)
# 输出结果
['(())', '()()']
采用深度优先搜索的方式解题:
<>
可以生出左枝叶的条件:左括号的剩余数量(严格)大于0:
可以生出右枝叶的条件:左括号剩余数量(严格)小于右括号剩余数量
采用动态规划的思路来解题: