22. Generate Parentheses

来源:互联网 发布:整形医院网络咨询收入 编辑:程序博客网 时间:2024/05/21 10:25

这里写图片描述

基本素养,只要见到求所有可能组合的情况(所有可能组合的个数), 首先立马想几个概念词:DFS、递归、回溯。有了这个直觉,你就省去了大量的时间,直接往递归上去套。接下来就是考虑怎么设计递归函数的问题了,速度自然会快很多。

这道题的要求是给定n对括号,生成所有正确的括号组合。这道题要生成正确形式的括号匹配的数量,其实就是卡特兰数。

卡特兰数,一种有着特殊规律的数列,先用一道题来引出卡特兰数。

10个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问有多少种排列方式?

我们可以先把这10个人从低到高排列,然后,选择5个人排在第一排,那么剩下的5个人肯定是在第二排。
用0表示对应的人在第一排,用1表示对应的人在第二排,那么含有5个0,5个1的序列,就对应一种方案。
比如0000011111就对应着
第一排:0 1 2 3 4
第二排:5 6 7 8 9
0101010101就对应着
第一排:0 2 4 6 8
第二排:1 3 5 7 9
所以,看到问题相应的转换为,这样的满足条件的01序列有多少个。
观察规律我们发现1的出现前边必须有一个相应的0对应,所以从左到右的所有序列中0的个数要一直大于1的个数。那这种数列有多少种排列方式呢?

那么我们从左往右扫描,第一次出现1的个数等于0的个数是第k位,那么在此之前,0的个数是大于1的个数的。在此之后,0的个数也是大于1的个数的。所以第k位0和1的个数第一次相等的排列有他们这两部分的个数相称的结果。那么所有的k有多少种,则把它们相加起来,就是最后的排列数。这是一个递归的问题。

即 a(n)=a(0)×a(n-1)+a(1)*a(n-2)+…+a(n-1)*a(0)

C语言版

#include<stdio.h>#include<stdlib.h>#include<string.h>void generater(char **result,char *temp,int n,int *returnSize,int left,int right){    if(right==n)    {        temp[left+right]='\0';        strcpy(result[(*returnSize)++],temp);        return;    }    if(left<n)    {        temp[left+right]='(';        generater(result,temp,n,returnSize,left+1,right);    }    if(right<left)    {        temp[right+left]=')';        generater(result,temp,n,returnSize,left,right+1);    }}char** generateParenthesis(int n, int* returnSize) {    int i;    char **result,*tmp;    tmp=malloc(sizeof(char)*(2*n+1));    result=malloc(sizeof(char*)*10000);    for(i=0;i<10000;i++)        result[i]=(char *)malloc(sizeof(char)*(2*n+1));    if(n>0)        generater(result,tmp,n,returnSize,0,0);    return result;}int main(){    int n,size=0,i;    char **result;    scanf("%d",&n);    result=(char **)malloc(sizeof(char*)*1000);    for(i=0;i<10000;i++)        result[i]=(char *)malloc(sizeof(char)*(2*n+1));    result=generateParenthesis(n, &size);     for(i=0;i<size;i++)        printf("%s\n",result[i]);    return 0;}

用二叉树形象的表示这种关系。然后再把二叉树转化为代码的形式。因为二叉树的定义就是递归定义的,因此本题很明显应该使用递归的形式。
这里写图片描述
从上面的图片中我们可以很明显的看到,最后五条画黑线的就是最终的结果,其中左分支都是添加左括号,又分支都是添加右括号。

那么我们在什么情况下添加左括号呢?很明显,最多能添加n个左括号,在递归调用的时候,在能传递到最底层的共用字符串中先添加”(“,然后left+1,递归调用就可以。

那什么时候添加右括号呢?当左括号个数大于右括号的个数时添加右括号。

C++版本

#include<iostream>#include<string>#include<vector>using namespace std;class Solution {public:    vector<string> generateParenthesis(int n)     {        vector<string> result;        string s;        if(n>0)            generatehelper(result,s,n,0,0);        return result;    }    void generatehelper(vector<string> &result,string &s,int n,int left,int right)    {        if(right==n)        {            result.push_back(s);        }        else        {            if(left<n)            {                s+="(";                generatehelper(result,s,n,left+1,right);                s.resize(s.size()-1);// s.erase(s.size()-1);该句话是为了实现回溯,考虑一下每次执行该句时上一句的递归一定已经实现了,所以需要去除最后一个括号            }            if(right<left)            {                s=s+")";                generatehelper(result,s,n,left,right+1);                s.resize(s.size()-1);            }        }    }};/*class Solution {public:    vector<string> result;    vector<string> generateParenthesis(int n) {        generate(0, 0, "", n);        return result;    }    void generate(int left, int right, string s, int n) {        if(right == n) {            result.push_back(s);        }        else        {            if(left < n)            {                generate(left + 1, right, s + "(", n);            }            if(right < left)            {                generate(left, right + 1, s + ")", n);            }        }    }};*/void main(){    Solution solve;    int N,i;    vector<string> s;    cin>>N;    s=solve.generateParenthesis(N);    for(i=0;i<s.size();i++)        cout<<s[i]<<endl;}

第二种回溯法程序:

class Solution {public:    vector<string> result;    vector<string> generateParenthesis(int n) {        generate(0, 0, "", n);        return result;    }    void generate(int left, int right, string s, int n) {        if(right == n) {            result.push_back(s);        }        else        {            if(left < n)            {                generate(left + 1, right, s + "(", n);            }            if(right < left)            {                generate(left, right + 1, s + ")", n);            }        }    }};
0 0
原创粉丝点击