Train Problem II(卡特兰数)

                                Train Problem II

题目链接 : 点这里

今天晚上有重新摸起来卡特兰数
前几项的卡特兰数为 :
1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, …

先把 递归和 递推的 两种通项说说吧

h(n) = h(n - 1) * (4 * n - 2) /( n+ 1)
//第一个 组合中 n 的意义是 选出n个0 (总的情况) 第二个组合数 的意思 不合法序列的数量 即 n + 1个 0 (这里等会再说 为什么是n + 1个 0)
h(n) = C(2n,n) / (n+1) = C(2*n,n) - C(2n,n+1)

就拿一个最简单的进栈和出栈为 例子
一个栈(无穷大)的进栈序列为1,2,3,…,n,有多少个不同的出栈序列?

我们来分析一下
假设第k 个数 要出栈 呢么 他一定是 把 这个序列 分成了 两部分 第一部分就是 1 ~k-1 (k - 1个数) 第二部分就是 k + 1 ~ n (n - k 个数)
那么此时 f(n) = f(k-1) * f(n- k) * 1(内部用乘) 假如 k 把所有的数都 取一遍 那么 此时 f(n) = f(0) * f(n- 1) + f(1) * f(n- 2) +…….. + f(n-1) * f(0) (外部用加)这里是不是就是卡特兰数的 通项了

对于每一个数 他肯定是必须要进栈一次出栈一次 假如 我们把 进栈的状态设为 ‘1’ 出栈的 状态设为 ‘0’ 要想使一个 进栈和出栈为 一个合法的序列 是不是 就要要求 从左 往右 ‘0’ 的 个数不能超过 ‘1’ 的个数,那么 一个 不合法的序列 肯定具备一个这样的特性 : 再 第 2 * m + 1 位 (只能是 奇数 位 我们可以想一下 他只有两个状态 0 和 1 要想让 0 的 个数 比 1 的个数 多一 那 我们就假设 再 第 k 位上 0 的个数 比 1 的 个数 多一个 那 吗 第k -1 之前 就一定有 m 的 1 和 m 个0 则 第k 位 就可以表示 成 2 * m + 1 )之前 ’0‘ 的个数 比 ‘1’ 的 个数 多一 此时 0 的个数 为 m + 1 个 , 前 2 * m + 1 位 一定有 m + 1 个 0 和 m 个 1 则 第2 * m + 2 ~ n 这个 区间里一定有 n - m - 1 个 0 (因为 一共有 n 个 0 和 n 个 1 ) 和 n- m 个1 假如 我们将 从 第 2 * m + 2 位 开始 将 0 与 1 互换 此时 整个序列不就是 有 n + 1 个 0 和 n - 1 个 1 那 我们 此时 求的 不和法的 序列 就转化成了 求 n + 1 个 0 还有 n - 1 个 1 (这二者之间一定是一一对应的)
故 h(n) = C(2n , n) - C(2n , n + 1);


import java.math.BigInteger;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        BigInteger []res = new BigInteger[104];
        //卡特兰数的前两项
        //h(n)=h(n-1)*(4*n-2)/(n+1);
        //非递归方式
        //递推 H(n) = (C(2*n,n) / n+ 1);
        res[0] = BigInteger.ONE;
        res[1] = BigInteger.ONE;
        for(int i = 2;i<=100;i++)
        {
            res[i] = res[i - 1].multiply(BigInteger.valueOf(4 * i - 2)).divide(BigInteger.valueOf(i+1));
        }
        int n ;
        Scanner cin = new Scanner(System.in);
        while(cin.hasNext())
        {
            n = cin.nextInt();
            System.out.println(res[n]);
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值