22. 括号生成

228 阅读3分钟

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例 1:

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]

解法一

递归 自己看官方答案之前,用递归实现的方法。

主要思想:

  1. 先初始化包含n个"("括号的数组
  2. 每次遍历数组,判断某个位置的左边的 "(" 比 ")" 多时,就在该位置插入")"
  3. 遍历一遍,插入一个")"
  4. 当每次插入一个")",产生的新数组,又从插入的位置开始遍历新的数组,重复步骤2和3
  5. 当数组长度等于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

力扣精选答案