不积跬步无以至千里——LeetCode 22.括号生成

给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。

例如,给出 = 3,生成结果为:

[
  "((()))",
  "(()())",
  "(())()",
  "()(())",
  "()()()"
]

 解题思路:

  1、利用递归,传入存储结果的列表,传入一个空字符串,和括号的对数,后来发现括号对数要分成左右个数。

  2、先添加 "(" 一种括号,在 n=0 时,添加 ")" ,再去掉一个 "(" ,添加 ")"再添"("  (反正就是先添加左括号,在不能添加时再添加右括号,结果加入list,返回到递归的去掉n=1,2,3...n个左括号的状态)

  3、后面查阅资料发现这是一种算法:回溯算法,后面做下具体记录

我的记录:

class Solution {
    public List<String> generateParenthesis(int n) {
        ArrayList<String> result = new ArrayList<String>();
        parenthes("", result, n, n);
        return result;
    }
    
    public void parenthes(String sublist, ArrayList result,int leftnum, int rightnum){
        if(leftnum == 0 && rightnum == 0){
            result.add(sublist);
        }
        if(leftnum > 0){
            parenthes(sublist + "(", result, leftnum - 1, rightnum);
        }
        if(rightnum > leftnum){
            parenthes(sublist + ")", result, leftnum, rightnum - 1);
        }
    }
}

LeetCode官方题解之回溯法:

只有在我们知道序列仍然保持有效时才添加 '(' or ')',而不是像方法一那样每次添加。我们可以通过跟踪到目前为止放置的左括号和右括号的数目来做到这一点,

如果我们还剩一个位置,我们可以开始放一个左括号。 如果它不超过左括号的数量,我们可以放一个右括号。

class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> ans = new ArrayList();
        backtrack(ans, "", 0, 0, n);
        return ans;
    }

    public void backtrack(List<String> ans, String cur, int open, int close, int max){
        if (cur.length() == max * 2) {
            ans.add(cur);
            return;
        }

        if (open < max)
            backtrack(ans, cur+"(", open+1, close, max);
        if (close < open)
            backtrack(ans, cur+")", open, close+1, max);
    }
}

复杂度分析

我们的复杂度分析依赖于理解 generateParenthesis(n) 中有多少个元素。这个分析超出了本文的范畴,但事实证明这是第 n 个卡塔兰数 \dfrac{1}{n+1}\binom{2n}{n}n+11(n2n),这是由 \dfrac{4^n}{n\sqrt{n}}nn4n 渐近界定的。

  • 时间复杂度:O(\dfrac{4^n}{\sqrt{n}})O(n4n),在回溯过程中,每个有效序列最多需要 n 步。

  • 空间复杂度:O(\dfrac{4^n}{\sqrt{n}})O(n4n),如上所述,并使用 O(n)O(n) 的空间来存储序列。 

LeetCode官方题解之闭合数法:

思路

为了枚举某些内容,我们通常希望将其表示为更容易计算的不相交子集的总和。

考虑有效括号序列 S 的闭包数:至少存在index> = 0,使得 S[0], S[1], ..., S[2*index+1]是有效的。 显然,每个括号序列都有一个唯一的闭包号。 我们可以尝试单独列举它们。

算法

对于每个闭合数 c,我们知道起始和结束括号必定位于索引 0 和 2*c + 1。然后两者间的 2*c 个元素一定是有效序列,其余元素一定是有效序列。

class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> ans = new ArrayList();
        if (n == 0) {
            ans.add("");
        } else {
            for (int c = 0; c < n; ++c)
                for (String left: generateParenthesis(c))
                    for (String right: generateParenthesis(n-1-c))
                        ans.add("(" + left + ")" + right);
        }
        return ans;
    }
}

复杂度分析

  • 时间和空间复杂度:O(\dfrac{4^n}{\sqrt{n}})O(n4n),该分析与回溯法类似。

猜你喜欢

转载自www.cnblogs.com/7long/p/10265818.html