数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
解法一
递归 自己看官方答案之前,用递归实现的方法。
主要思想:
- 先初始化包含n个"("括号的数组
- 每次遍历数组,判断某个位置的左边的 "(" 比 ")" 多时,就在该位置插入")"
- 遍历一遍,插入一个")"
- 当每次插入一个")",产生的新数组,又从插入的位置开始遍历新的数组,重复步骤2和3
- 当数组长度等于2n时,意味着有n对括号了,就添加到结果数组里面
def generateParenthesis1(n):
def judgeCanInsert(index, ls):
"""判断数组ls中index左边的所有元素,是否左半边的括号大于右半边的括号"""
leftCount, rightCount = 0, 0
for ch in ls[:index]:
if ch == "(":
leftCount += 1
else:
rightCount += 1
return True if leftCount > rightCount else False
# 初始化左半边括号,先用数组存储
arr = ["("] * n
ans = [] # 用于记录结果的数组
def insertRightParenthesis(start, n, arr):
temp = arr.copy() # 每次要对新传入的数组深拷贝,避免改了传进来的数组
if len(temp) == n * 2 and "".join(temp) not in ans:
ans.append("".join(temp)) # 当数组长度达到2n,并且数组中没有出现过该元素时,就添加
# 一个一个插入右半边括号
# 每次判断 某个位置的左边的 "(" 比 ")" 多时,就在该位置插入
# 遍历一遍,插入一个")"
for i in range(start, len(temp)):
if judgeCanInsert(i + 1, temp):
# 当"(" 比 ")" 多时,就插入一个")"
temp.insert(i + 1, ")")
# 每次新插入一个")"时,就从该位置又继续依次遍历
for m in range(i + 1, len(temp)):
insertRightParenthesis(m, n, temp)
# 从不同位置开始
for j in range(n):
insertRightParenthesis(j, n, arr)
return ans
解法二
回溯 深度优先遍历 回溯的问题基本都可以抽象成树形结构问题。
使用数组的解法:
def generateParenthesis2(n):
ans = []
def backtrack(arr, left, right):
# 定义出口:当S数组长度为2n时,添加到结果数字中
if len(arr) == 2 * n:
ans.append("".join(arr))
return # 这里return也是回溯,即找到一个结果过后,回到上面的节点,重新找其他结果
if left < n:
arr.append("(") # 如果左括号小于n,就添加左括号
backtrack(arr, left + 1, right) # 继续递归找这一支下面的可能结果
# 这里是回溯的本质,因为上面递归调用回来过后,代表上面 arr.append("(") 这一步的可能结果寻找完了
# 需要将 arr.append("(") 回溯,即执行pop()操作,寻找其他的可能结果
arr.pop()
if right < left:
arr.append(")") # 如果右括号小于左括号,就添加右括号
backtrack(arr, left, right + 1)
arr.pop()
backtrack([], 0, 0) # 初始事,结果数组为空,左右括号都为0
return ans
使用字符串的解法:
def generateParenthesis3(n):
def dfs(n, path, res, left, right):
# 当左括号大于n,或者右括号大于左括号时就进行回溯
if left > n or right > left: return
# 定义出口:当path的长度为2n时,就添加到结果中
if len(path) == 2 * n:
res.append(path)
return
else:
# 字符串自带回溯,不用学数组写pop()
dfs(n, path + "(", res, left + 1, right)
dfs(n, path + ")", res, left, right + 1)
res = []
if n <= 0: return res
dfs(n, "", res, 0, 0) # 开始左右括号都为0,路径path也为空""
return res
字符串的另一种解法:
def generateParenthesis4(n):
def dfs(n, path, res, left, right):
if len(path) == 2 * n:
res.append(path)
return
else:
# 字符串自带回溯,不用学数组写pop()
if left < n:
# 如果左括号小于n,就添加左括号
dfs(n, path + "(", res, left + 1, right)
if right < left:
# 如果右括号小于左括号,就添加右括号
dfs(n, path + ")", res, left, right + 1)
res = []
if n <= 0: return res
dfs(n, "", res, 0, 0) # 开始左右括号都为0,路径path也为空""
return res