题目描述:
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且有效的括号组合。
示例:
输入:n = 3
输出:[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
解题思路一
类似的需要考虑所有组合可能性的问题,一般都离不开递归和回溯法,或者BFS、DFS。
列出所有可能的括号组合,然后剔除其中无效的括号组合。
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
def generate(A):
if len(A) == 2*n:
if valid(A):
ans.append("".join(A))
else:
A.append('(')
generate(A)
## 添加左括号,直到A长度等于2n
A.pop()
## pop最后一个左括号,添加一个右括号,进行不同的组合
A.append(')')
generate(A)
## 添加一个右括号,直到A长度等于2n
A.pop()
## pop 最后一个右括号,进行不同的组合
## 重复以上pop和append过程,得到所有有效的括号组合
def valid(A):
bal = 0
for c in A:
if c == '(':bal += 1
else:bal -= 1
if bal < 0:return False
return bal == 0
ans = []
generate([])
return ans
时间复杂度分析:
总共有2n个位置,每个位置都有'(',')'两种选择,所以列举出的可能组合一共有种,由于每一种组合都需要进行有效性验证,而验证一个组合的有效性要操作n次,所以时间复杂度
空间复杂度分析:
每次递归时产生的空间是,总共进行了2n次递归,因此空间复杂度为
解题思路二
回溯法进行递归,参考官方题解
我们可以只在序列仍然保持有效时才添加 '(' or ')',而不是像 方法一 那样每次添加。我们可以通过跟踪到目前为止放置的左括号和右括号的数目来做到这一点,
如果左括号数量不大于 n,我们可以放一个左括号。如果右括号数量小于左括号的数量,我们可以放一个右括号。
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
ans = []
def backtrack(S, left, right):
if len(S) == 2 * n:
ans.append(''.join(S))
return
# 每一个有效括号组合的长度都是2n,并且左、右括号各有n个,数量相同
# 如果左括号小于n个,那么就加一个左括号
if left < n:
S.append('(')
backtrack(S, left+1, right)#把左括号加满
S.pop()#进行不同的组合
## 如果右括号的数据小于左括号,那么就添加一个右括号,
if right < left:
S.append(')')
backtrack(S, left, right+1)#把右括号加满
S.pop()#进行不同的组合
backtrack([], 0, 0)
return ans
我们的复杂度分析依赖于理解 generateParenthesis(n) 中有多少个元素。这个分析超出了本文的范畴,但事实证明这是第 nn 个卡特兰数 这是由
渐近界定的。
时间复杂度:,在回溯过程中,每个答案需要 O(n) 的时间复制到答案数组中。
空间复杂度:O(n),除了答案数组之外,我们所需要的空间取决于递归栈的深度,每一层递归函数需要 O(1) 的空间,最多递归 2n 层,因此空间复杂度为 O(n)。
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/generate-parentheses/solution/gua-hao-sheng-cheng-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
总结
对于任何用到递归体的算法,都必须要明确递归体的最小单位,以及递归终止条件。
思路一思路二的递归终止条件都是当前组合的长度到达最大长度2n
思路一思路二的递归体的最小单位都是添加一个左括号'(',或者添加一个右括号')'。
不同的是添加左括号和右括号的条件有区别。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/generate-parentheses