• LeetCode(C++)刷题计划:22-括号生成


    22-括号生成

    @Author:CSU张扬
    @Email:csuzhangyang@gmail.com or csuzhangyang@qq.com

    Category Difficulty Pass rate Tags Companies
    algorithms Medium 72.20% string / backtracking google / uber / zenefits

    1. 题目

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

    例如,给出 n = 3,生成结果为:
    
    [
      "((()))",
      "(()())",
      "(())()",
      "()(())",
      "()()()"
    ]
    

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/generate-parentheses/

    2. 解法

    2.1 解法一:回溯

    n = 3 为例:我们的字符串 s 一共有 6 个位置来放置 '('')'

    1. 首先我们知道:第一个位置一定是 '(',此时 s = ( _ _ _ _ _
    2. 此时我们考虑第二个位置,我们选择可以放置'('')'
      那么什么情况下,我们可以有两个选择呢?
      很容易想到,应该是当 '(' 的数量大于 ')' 的数量 并且 '(' 的数量小于 n 时,即 if (left < N && left > right)
      可以思考 s = ( ( ) _ _ _s = ( ( ( ) _ _这两种情况下,下一个位置应该放哪种括号。
    3. 步骤2中,我们可以有两个选择。那么我们接下来就应该考虑什么情况下只有一种选择。
    4. 只能放置 '('
      易知,当 '(' 的数量等于 ')' 的数量时,我们只能向后添加 '('
      可以思考 s = ( ( ) ) _ _s = ( ) ( ) _ _这两种情况下,下一个位置应该放哪种括号。
    5. 只能放置 ')'
      易知,当 '(' 的数量等于 n 时,我们只能向后添加 ')'
      可以思考 s = ( ( ( _ _ _s = ( ) ( ( _ _这两种情况下,下一个位置应该放哪种括号。

    我们的回溯函数 void backtrack(int left, int right, const string &s) 中,leftright 代表的是 s 中左右括号的数量。
    left + right == 2 * N 时,回溯结束。

    注意:
    初始情况下,我们必须要先添加一个 '(',此时 s = ( _ _ _ _ _,所以参数 left = 1, right = 0

    执行用时: 4 ms, 在所有 cpp 提交中击败了96.60%的用户
    内存消耗: 17.4 MB, 在所有 cpp 提交中击败了36.95%的用户

    class Solution {
    public:
        vector<string> res;
        int N;
        vector<string> generateParenthesis(int n) {
            N = n;
            string s = "";
            backtrack(1, 0, s + "(");
            return res;
        }
        void backtrack(int left, int right, const string &s) {
            if (left + right == 2 * N) {
                res.push_back(s);
                return;
            }
            if (left < N && left > right) {
                backtrack(left + 1, right, s + "(");
                backtrack(left, right + 1, s + ")");
            } else if (left == N) {
                backtrack(left, right + 1, s + ")");
            } else if (left == right) {
                backtrack(left + 1, right, s + "(");
            }
        }
    };
    

    2.2 解法二:动态规划

    参考 rockrock2Yuyu

    首先看 n 较小时的结果。

    1. n = 0 是,res = { "" },为空。
    2. n = 1 是,res = { "()" }
    3. n = 2 是,res = { "(())", "()()" }
    4. n = 3 是,res = { "((()))","(()())","(())()","()(())","()()()" }

    问题来了,你没有考虑过每一个 n 的结果,都和比它小的 n 的结果,有点关联?

    我们可以这么看待这个问题:

    1. n = i 的结果其实就是比 n = i - 1 多了一对括号。我们可能会想,那么这对括号应该如何放置呢?而事实上,我们应该这样想,那么 n = 1..i-1 的结果,应该如何放到这对括号里呢?也就是这对括号,是不动的。
    2. 我们只有两个地方可以放,一是这一对括号内部,二是括号外部。
      外部: 其实放在括号左侧或者右侧都行。但是放在右侧,结果会按照字典序排列,因此我们选择放在右侧。但是要知道,放在左侧也是可以的。
    3. 我们要对所有 n < i 的情况遍历,要保证最后括号一共 i 对。
      1. 所以如果内部放 n = 0 的结果,右侧就要放 n = i - 1 的结果,排列所有情况。
      2. 如果内部放 n = 1 的结果,右侧就要放 n = i - 2 的结果,排列所有情况。
      3. 以此类推。。。
        最后,内部放 n = i - 1 的结果,右侧就要放 n = 0 的结果,排列所有情况。
    4. 我们可以得出状态方程:dp[i] = '(' + dp[k] + ')' + dp[i-1-k], k = 0..i-1

    执行用时: 8 ms, 在所有 cpp 提交中击败了82.13%的用户
    内存消耗: 9.9 MB, 在所有 cpp 提交中击败了97.08%的用户

    // dp[0] = ""
    // dp[i] = '(' + dp[k] + ')' + dp[i-1-k], k = 0..i-1 (按字典序)
    // 或者dp[i] = dp[k] + '(' + dp[i-1-k] + ')', k = 0..i-1 (非字典序)
    class Solution {
    public:
        vector<string> generateParenthesis(int n) {
            vector< vector<string> > dp(n + 1, vector<string>());
            dp[0] = {""};
            for (auto i = 1; i < n + 1; ++ i) {
                for (auto k = 0; k < i; ++ k) {
                    for (auto s1 : dp[k]) {
                        for (auto s2 : dp[i - 1 - k]) {
                            dp[i].push_back("(" + s1 + ")" + s2);
                        }
                    }
                }
            }
            return dp[n];
        }
    };
    
  • 相关阅读:
    人工智能 有信息搜索 (启发式)
    python学习之高阶函数
    文件学习
    codeblock快捷键使用
    React项目之BrowserRouter路由方式之-------生产环境404问题
    React生产环境打包&&后台环境运行(有跨域+无跨域)
    React前台改用HashRouter并解决两个问题
    React路由基础
    React前台404组件页面+路由控制重定向
    react调用方法
  • 原文地址:https://www.cnblogs.com/MagicConch/p/12179148.html
Copyright © 2020-2023  润新知