LeetCode22括号生成

原题目

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

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

[ “((()))”, “(()())”, “(())()”, “()(())”, “()()()” ]

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

题目大意

将n对括号组合成正确的形式,即每个左括号都有一个右括号与之匹配。如n=3时,")(()()"第一个右括号没有对应左括号,所以错误。

具体代码
1.暴力法

二进制暴力法,即将其看成是一个二进制,‘(’看作1,‘)’看作0,
这样就可以确定区间。
同样当n=3时
5种情况用二进制表示为:
[111000,110100,110010,101100,101010]
可以发现他的取值范围为[101010,111000].十进制为[42,56].
同理当n=4时,取值范围为[10101010,11110000],十进制为[170,240]
所以用公式求出其最小值和最大值 a和b

for(int i=0; i<n; i++)
    {
        b=b+pow(2,n+i);
        a=a+pow(2,i*2+1);
    }

遍历两者之间的所有数字,寻找里面所有符合条件的数,转变为二进制1为"(", 0为")"

char ** generateParenthesis(int n, int* returnSize){
    *returnSize=0;
    int a=0,b=0;
    for(int i=0;i<n;i++)
    {
        b=b+pow(2,n+i);
        a=a+pow(2,i*2+1);
    }
    char *str1;
    char **str2;
    str1=(char *)malloc(sizeof(char)*10000);
    str2=(char **)malloc(sizeof(char *)*10000);
    for(int i=0;i<10000;i++)
        str2[i]=(char *)malloc(sizeof(char)*10000);
    //printf("%d %d\n",a,b);

    for(int i=b;i>=a;i--)
    {
        int len=n*2;int flag=0;
        str1[len]='\0';
        int k=i;
        while(k)
        {
            if(k%2==1)
               {
                 str1[--len]='(';
                 flag+=1;
                if(flag>0)break;
               }
               else
               {
                   str1[--len]=')';
                   flag-=1;
               }
               k=k/2;
        }
        if(flag==0)
        {
            strcpy(str2[(*returnSize)++],str1);
        }
    }
    return str2;
}
class Solution {
public:
    vector<string> generateParenthesis(int n) {
        vector<string>res;
        long long  low = 0, high = 0;
        //求区间范围(101010,111000)
        for(int i = 1; i <= n; i++){
            high += 1 << (2*n-i);
            low += 1 << (i*2-1);
        }
        //遍历所有值
        for(long long i = high; i >= low; i--){
            long long num = i;
            string s;
            int flag = 0;
            while(num){
                if(num%2==1){
                    s = "(" + s;
                    flag++;
                    if(flag>0)break;
                }else{
                    s = ")" + s;
                    flag--;   
                }
                num /= 2;
            }
            if(flag==0)
                res.push_back(s);
        }
        return res;
    }
};
2.dfs+剪支

按照规定,添加括号,左括号数要小于n个,右括号数要小于左括号数

class Solution {
public:
    vector<string>res;
    void dfs(string s, int left, int right, int n){//左边 ,右边
        if(left == n && right == n){
            res.push_back(s);
            return;
        }
        if(left < n)
            dfs(s+"(",left+1,right,n);
        if(left >right)
            dfs(s+")",left,right+1,n);
    }
    vector<string> generateParenthesis(int n) {
        dfs("",0,0,n);
        return res;
    }
};
3.动态规划

由归纳法得出规律:
当我们清楚所有 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) 时,按上述方式取的括号组合一定不同。

class Solution {
public:
    vector<string> generateParenthesis(int n) {
        vector<vector<string>>dp(n+1);
        dp[0] = {""};
        dp[1] = {"()"};
        string s;
        for(int i = 2; i <= n; i++){
            for(int j = 0; j < i; j++){
                for(string a : dp[j]){
                    for(string b : dp[i-j-1]){
                        s = "(" + b + ")" + a;
                    }
                }
                dp[i].push_back(s);
            }
        }
        return dp[n];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Baal Austin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值