跳转至

*22.括号生成 (Medium)*

题目描述*

标签*

回溯算法

思路 & 代码*

又是回溯,套模板就行了,时间复杂度为卡塔兰数 C_n = \frac{1}{n + 1} \binom{2n}{n},这个数很有意思,比如给定 1 到 n 的入栈序列,合法的出栈序列数目也是卡塔兰数,括号匹配跟栈差不多。卡塔兰数渐近表示为 C_n \sim \frac{4^n}{n^{3/2}\sqrt{\pi}}

另一种思路,首个字符肯定是左括号,然后当向后添加直到第一次左右括号平衡时,记右括号位置为 cur,那么 1 ~ cur - 1 之间的一定是合法的序列,cur + 1 ~ 2n - 1 也是合法序列。共 n 组括号,1 到 cur - 1 之间有 a 组,cur + 1 到 2n - 1 之间是 n - 1 - a 组,而每个合法序列都会有一个唯一的 cur,因此对 n 组括号的所有序列,只需知道 a 组括号以及 n - 1 - a 组括号的所有序列,然后两两组合即可。

class Solution {
public:
    vector<string> generateParenthesis(int n) {
        vector<string> res;
        if(n == 0) {
            return res;
        }
        backtrack(res, 0, 0, n, "");
        return res;     
    }
    void backtrack(vector<string>& res, int l, int r, int n, string path) {
        if(path.length() == 2 * n) {
            res.push_back(path);
            return;
        }
        if(l < n) {
            backtrack(res, l + 1, r, n, path + "(");
        }
        if(r < l) {
            backtrack(res, l, r + 1, n, path + ")");
        }
    }
};
class Solution {
    shared_ptr<vector<string>> cache[100] = {nullptr};
public:
    shared_ptr<vector<string>> generate(int n) {
        if (cache[n] != nullptr)
            return cache[n];
        if (n == 0) {
            cache[0] = shared_ptr<vector<string>>(new vector<string>{""});
        } else {
            auto result = shared_ptr<vector<string>>(new vector<string>);
            for (int i = 0; i != n; ++i) {
                auto lefts = generate(i);
                auto rights = generate(n - i - 1);
                for (const string& left : *lefts)
                    for (const string& right : *rights)
                        result -> push_back("(" + left + ")" + right);
            }
            cache[n] = result;
        }
        return cache[n];
    }
    vector<string> generateParenthesis(int n) {
        return *generate(n);
    }
};
class Solution {
public:
    vector<string> generateParenthesis(int n) {
        vector<string> res;
        if(n == 0) {
            return res;
        }
        vector<vector<string>> dp(n + 1);
        dp[0] = { "" };
        dp[1] = { "()" };
        for(int i = 2; i <= n; i++) {
            for(int j = 0; j < i; j++) {
                for(auto& p : dp[j]) {
                    for(auto& q : dp[i - j - 1]) {
                        dp[i].push_back("(" + p + ")" + q);
                    }
                }
            }
        }
        return dp[n];
    }
};

最后更新: July 23, 2022