LeetCode c语言-Generate Parentheses和买票找零问题

Title:

Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.

For example, given n = 3, a solution set is:

[
  "((()))",
  "(()())",
  "(())()",
  "()(())",
  "()()()"
]

这道题目难度颇高,如果没有正确的思路出发点,是很难做出来的。

典型的递归+栈问题。一般碰到要输出很多种结果的问题,递归是第一考虑的思路。

对于这道题,符合要求的序列一定满足以下条件:

从左边开始数,右括号的个数一定不可能大于左括号,否则会出现))这种情况。

而且第一个一定是左括号。


代码如下:

solution:

/**
 * Return an array of size *returnSize.
 * Note: The returned array must be malloced, assume caller calls free().
 */

void generate(char** result, int* Size, int l, int r, char* tmp, int index) {
    if(l==0 && r==0) {
        tmp[index]=0;
        result[*Size]=(char*)malloc(sizeof(char)*index);
        strcpy(result[*Size],tmp);
        (*Size)++;
        return;
    }
    if (l>0) {
        tmp[index]='(';
        generate(result, Size, l-1, r, tmp, index+1);
    }
    if(r>0 && l<r) {
        tmp[index]=')';
        generate(result, Size, l, r-1, tmp, index+1);
    }
}
char** generateParenthesis(int n, int* returnSize) {
    char** result=(char**)malloc(sizeof(char)*1000000);
    char* tmp=(char*)malloc(sizeof(char)*(n*2+1));  
    int l=n,r=n; /* l和r分别表示左括号和右括号的剩余个数 */
    
    *returnSize=0;  
    generate(result,returnSize,l,r,tmp,0);  
    return result;  
}


解析递归函数:


l和r表示剩余的左括号和右括号。

那么当l>0时,可以插入左括号,记住左括号是只要有就可以插入的。然后进行递归,记住l-1,表示减少一个。r不变。

    if (l>0) {
        tmp[index]='(';
        generate(result, Size, l-1, r, tmp, index+1);
    }



当r>0时,还要注意,一定要l<r,也就是剩余的l小于r,那么已经插入的l肯定大于r,这个时候才可以插入右括号。因为要始终保证,左括号大于等于右括号。这个序列才有效。

   if(r>0 && l<r) {
        tmp[index]=')';
        generate(result, Size, l, r-1, tmp, index+1);
    }



当l==0 并且r==0,表明全部插入,这个时候说明这个序列是有效的,可以存起来并返回。

    if(l==0 && r==0) {
        tmp[index]=0;
        result[*Size]=(char*)malloc(sizeof(char)*index);
        strcpy(result[*Size],tmp);
        (*Size)++;
        return;
    }




解析到这里,其实能够看出来,如果找到了左括号数量一定要大于右括号的隐含要求,再配合递归,其实非常简单。关键是能不能找到这个要求。


在《编程之美》一书中,也有类似的问题:买票找零


《编程之美》4.3买票找零:2n个人排队买票,其中n个人持50元,n个人持100元。每张票50元,且一人只买一张票。初始时售票处没有零钱找零。请问这2n个人一共有多少种排队顺序,不至于使售票处找不开钱?


这道题其实和括号匹配问题是一样的,50元的相当于左括号,100元相当于右括号,一定要左括号大于右括号才能成立。


而且这种类型的题目牵扯到一个公式:Catalan number


比如对这道找零的题目进行数学分析:

分析1:队伍的序号标为0,1,…,2n-1,并把50元看作左括号,100元看作右括号,合法序列即括号能完成配对的序列。对于一个合法的序列,第0个一定是左括号,它必然与某个右括号配对,记其位置为k。那么从1到k-1、k+1到2n-1也分别是两个合法序列。那么,k必然是奇数(1到k-1一共有偶数个),设k=2i+1。那么剩余括号的合法序列数为f(2i)*f(2n-2i-2)个。取i=0到n-1累加即: 
f(2n)=f(0)*f(2n-2)+f(2)*f(2n-4)+······+f(2n-4)*f(2)+f(2n-2)*f(0) 
并且令f(0)=1,再由组合数C(0,0)=0,可得 

以上就是一种卡特兰数的通项公式。


Catalan 的应用场景:


1.出栈次序(买票问题)


对于一个无限大的栈,一共n个元素,请问有几种合法的入栈出栈形式?


分析:n个元素出栈入栈操作共有2n个,且任何前x个操作中入栈操作必须不少于出栈操作,直接用f(2n)计算即可。



2.括号化问题(矩阵连乘问题)


P = a1 * a2 * a3 * … * an,其中ai是矩阵。根据乘法结合律,不改变矩阵的相互顺序,只用括号表示成对的乘积,试问一共有几种括号化方案?


分析:n个矩阵相乘需要n-1对括号,且任何前x个元素中”(”的个数一定大于”)”的个数,所以应该为f(2(n-1))


3.街区对角问题

某个城市的某个居民,每天他须要走过2n个街区去上班(他在其住所以北n个街区和以东n个街区处工作)。如果他不跨越(但可以碰到)从家到办公室的对角线,那么有多少条可能的道路? 
这里写图片描述



分析:其实也与括号问题相似,这个人一共要走2n步,其中向右与向上分别n步,那么,假设他第一步是向右的,那么之后的任何时刻,他向右的步数都不能少于想上的步数,即f(2n),当然,他也可以第一步时先向上,同样有f(2n)种走法,两者应该是以对角线对称的,所以答案为2*f(2n)。




转载于:https://www.cnblogs.com/sichenzhao/p/9320227.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值