LeetCode-22. 括号生成

该博客介绍了LeetCode第22题的解决方案,主要讲解了动态规划的解法。通过分析当n=3时的示例,解释了如何递归地生成所有有效括号组合,并提供了详细思路,强调了关键在于如何处理新增括号的放置位置。此外,还提及了解法2——暴力法,但未展开说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LeetCode-22. 括号生成

题目

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

示例 1:

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

示例 2:

输入:n = 1
输出:["()"]

提示:

  • 1 <= n <= 8

解法

解法1 :dp

思路:
当我们清楚所有 i<n 时括号的可能生成排列后,对与 i=n 的情况,我们考虑整个括号排列中最左边的括号。
它一定是一个左括号,那么它可以和它对应的右括号组成一组完整的括号 “( )”,我们认为这一组是相比 n-1 增加进来的括号。

那么,剩下 n-1 组括号有可能在哪呢?

【这里是重点,请着重理解】

剩下的括号要么在这一组新增的括号内部,要么在这一组新增括号的外部(右侧)。

既然知道了 i<n 的情况,那我们就可以对所有情况进行遍历:

“(” + 【i=p时所有括号的排列组合】 + “)” + 【i=q时所有括号的排列组合】

其中 p + q = n-1,且 p q 均为非负整数。

事实上,当上述 p 从 0 取到 n-1,q 从 n-1 取到 0 后,所有情况就遍历完了。

注:上述遍历是没有重复情况出现的,即当 (p1,q1)≠(p2,q2) 时,按上述方式取的括号组合一定不同。

/*
dp[i]:表示i组括号中的所有有效组合
dp[i] = "(dp[p]的所有有效组合)+【dp[q]的组合】",其中 1 + p + q = i , p从0遍历到i-1, q则相应从i-1到0
*/

class Solution {
public:
    vector<string> generateParenthesis(int n) {
        //简单动态规划
        if(n == 0) return {};
        if(n == 1) return { "()"};
        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(string p : dp[j]){
                    for(string q: dp[i-j-1]){
                        string str = "(" + p + ")" + q;
                        dp[i].push_back(str);
                    }
                }
            }
        }
        return dp[n];
    }
};

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

笔记

解法2:暴力法



class Solution {
/*暴力法:我们可以生成所有 2^{2n}个 '(' 和 ')' 字符构成的序列,然后我们检查每一个是否有效即可。
思路:为了生成所有序列,我们可以使用递归。长度为 n 的序列就是在长度为 n-1 的序列前加一个 '(' 或 ')'。

为了检查序列是否有效,我们遍历这个序列,并使用一个变量 balance 表示左括号的数量减去右括号的数量。如果在遍历过程中 balance 的值小于零,或者结束时 balance 的值不为零,那么该序列就是无效的,否则它是有效的。

*/
    bool valid(const string& str){
        int balance = 0;
        for(char c: str){
            if(c == '('){
                balance++;
            }else{
                balance--;
            }
            if(balance < 0){ //遍历过程中
                return false;
            }
            
        }
        return balance == 0;  //结束时
    }

    void generate_all(string& current, int n, vector<string>& result){
        if(n == current.size()){
            if(valid(current)){
                result.push_back(current);
            }
            return;
        }
// 递归
        current += '(';
        generate_all(current,n,result);
        current.pop_back();
        current += ')';
        generate_all(current,n,result);
        current.pop_back();

    }
public:
    vector<string> generateParenthesis(int n) {
        vector<string> result;
        string current;
        generate_all(current,n*2,result);
        return result;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值