卡特兰数归纳

卡特兰数

  • 注CSDN这里图片好像不支持缩放这样子,而且这公式支持真的稀烂。。
参考
卡特兰数定义
  • 卡特兰数是一种经典的组合数,经常出现在各种计算中,其前几项为 : 
    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, ...
    
  • 卡特兰数到递推式:

    • f ( n ) = ∑ i = 0 n − 1 f ( i ) ∗ f ( n − 1 − i ) f(n) = \sum_{i=0}^{n-1}f(i)\ast f(n-1-i) f(n)=i=0n1f(i)f(n1i)
  • 卡特兰数到通式:

    • f ( n ) = C 2 n n n + 1 f(n) = \frac{C_{2n}^n}{n+1} f(n)=n+1C2nn
从递推式到通式到证明——母函数法
  • 上面提到,卡特兰数到递推式可以写成:

  • 那么卡特兰数到母函数(bilibili-母函数)可以设成:

在这里插入图片描述

  • 由于递推式中出现了两个元素乘积,因此,先求 F 2 ( x ) F^2(x) F2(x)

在这里插入图片描述

  • 于是我们可以取错位相减:

  • 然后解方程(看成 a x 2 − x = − 1 ax^2-x = -1 ax2x=1​)得:

在这里插入图片描述

  • lim ⁡ x − > 0 + F ( x ) = f ( 0 ) = 1 \lim_{x->0^+} F(x) = f(0) = 1 limx>0+F(x)=f(0)=1​ 可得:

在这里插入图片描述

  • 很显然,应该保留 F ( x ) = 1 − 1 − 4 x 2 x F(x) = \frac{1 - \sqrt {1 - 4x}}{2x} F(x)=2x114x ​​

  • 接下将F(x)用级数拆开:
    在这里插入图片描述

  • 又因为 F ( x ) = ∑ n = 0 ∞ f ( n ) x n F(x) = \sum_{n=0}^\infty f(n)x^n F(x)=n=0f(n)xn,我们可以得出 f ( n ) f(n) f(n)的公式为:

    • f ( n ) = ( 2 n n ) n + 1 = = C 2 n n n + 1 f(n) = \frac{ \left( \begin{array}{c} 2n \\ n \end{array} \right)}{n+1} = =\frac{C_{2n}^n}{n+1} f(n)=n+1(2nn)==n+1C2nn

    • 至此得到通项,于是我们知道了通项是怎么来的了

从通式到通式的递推公式推导
  • 这部分原本是写在作业里的,因此命名可能会有点不一致,总之可以用通式的下一项 C a t a l a n n − 1 = C 2 n − 2 n − 1 n = 1 n ∗ ( 2 n − 2 ) ! ( n − 1 ) ! ∗ ( n − 1 ) ! Catalan_{n-1} = \frac{C^{n-1}_{2n-2}}{n} = \frac{1}{n}*\frac{(2n-2)!}{(n-1)!*(n-1)!} Catalann1=nC2n2n1=n1(n1)!(n1)!(2n2)!得到递推式:
    在这里插入图片描述
通用模板
  • 模板式根据通式的递推公式来写的

  • def catalan(self, n: int) -> int:
        if n == 0 or n == 1:
            return 1
        return (4 * n - 2) * self.catalan(n - 1) // (n + 1)
    
应用举例
进出栈序列
  • 题目描述

    n 个元素进栈序列为:1,2,3,4,...,n,则有多少种出栈序列

  • 找张图来说明:

    • 我们假设第k元素( k ∈ 1 ⋯ n k\in 1\cdots n k1n)为最后一个出栈的元素,那么在此之前有k-1个元素已经出栈了,在此之后还有n-k-1个元素需要在k之前出栈,那么我们可以得到两部分: f ( k − 1 ) ∗ f ( n − k − 1 ) f(k-1)\ast f(n-k-1) f(k1)f(nk1),其中 f ( n ) f(n) f(n)表示计算有n个元素的出栈可能数的函数
    • 然后( k ∈ 1 ⋯ n k\in 1\cdots n k1n​),我们就得到了 f ( n ) = ∑ i = 1 n f ( i ) ∗ f ( n − i ) f(n) = \sum_{i=1}^{n}f(i)\ast f(n-i) f(n)=i=1nf(i)f(ni)​​,这就是卡特兰数的递推式~,于是可以直接用通式来解了
括号序列
  • 题目描述

    n 对括号,则有多少种 “括号匹配” 的括号序列

  • 找张图来说明:

    • 这个问题其实和进出栈道问题十分类似,一般用栈解决(即使不用卡特兰),我们假设第k个‘(’是最后一个出栈道括号,那么之前有k-1个‘(’已经出栈,之后还有n-k-1个‘(’括号。。。。。。然后套公式
二叉树
  • 题目描述

    • n + 1 个叶子节点能够构成多少种形状不同的(国际)满二叉树
    • (国际)满二叉树定义:如果一棵二叉树的结点要么是叶子结点,要么它有两个子结点,这样的树就是满二叉树
  • 根据国际满二叉树的定义,由n + 1 个叶子节点可知二叉树一共有2n个节点

  • 我们不妨设二叉树扩展的时候为先左叶子节点后右叶子节点的顺序(因为这个不影响结果,反过来也是可以的,但是一定要左右都有才满足条件)

  • 然后不妨假设第2k个节点是最后被扩展的右节点,在此之前(即该节点的兄弟节点被扩展之前)有k-1个右节点被扩展,之后(即该节点的兄弟节点被扩展之后)有n-k-1个右节点要在这个之前被扩展。。。然后就变成了括号匹配问题。。。然后用模版套上去就好了

电影购票
  • 题目描述
    • 电影票一张 50 coin,且售票厅没有 coin。m 个人各自持有 50 coin,n 个人各自持有 100 coin。则有多少种排队方式,可以让每个人都买到电影票。
  • 持有 50 coin 的人每次购票时不需要找零,并且可以帮助后面持有 100 coin 的人找零;而对于持有 100 coin 的人每次购票时需要找零,但 100 coin 对后面的找零没有任何作用。因此,**相当于每个持有 100 coin 的人都需要和一个持有 50 coin 的人进行匹配。**于是就要求50在买的时候一定有100在此等候找零,此时又回到了括号匹配问题(进出栈问题)。。。然后套模板
凸n边形的不同划分方式
  • 这道是作业题:

    • Given a convex polygon with n vertices, we can divide it into several separated pieces, such that every piece is a triangle. When n = 4, there are two different ways to divide the polygon; When n = 5, there are five different ways.
      Give an algorithm that decides how many ways we can divide a convex polygon with n vertices into triangles.
      
    • 在这里插入图片描述

    • 大概意思就是凸n边形的三角形划分种类,如凸4边形右2种,凸5边形有5种这样子

    • 思路大概是这样的,以五边形为例,我们先编号,然后固定一个点(这里是3):

      • 在这里插入图片描述
    • 然后把多边形划分成两个部分,左侧是k+1边形(4边形),下册是m-k+1边形(5-3+1),于是可以写出 f ( 4 ) ∗ f ( 5 + 1 − 3 ) f(4)\ast f(5+1-3) f(4)f(5+13)

      • (为了后面好区分,我把n换成了m)
    • 归纳一下就可以写出递推式 f ( n ) = ∑ i = 2 m − 2 f ( i + 1 ) ∗ f ( m + 1 − i ) f(n) = \sum_{i=2}^{m-2}f(i+1)\ast f(m+1-i) f(n)=i=2m2f(i+1)f(m+1i),但是我们发现这好像一点区别,为了保持一致,令m-2=n,于是得到 f ( n ) = ∑ i = 0 n − 1 f ( i ) ∗ f ( n − 1 − i ) f(n) = \sum_{i=0}^{n-1}f(i)\ast f(n-1-i) f(n)=i=0n1f(i)f(n1i)​​,这就可以套公式了,区别就是5边形这个玩意相当于卡特兰的n=3这样子

  • 代码:

    • class Solution:
          def catalan(self, n: int) -> int:
              if n == 0 or n == 1:
                  return 1
              return (4 * n - 2) * self.catalan(n - 1) // (n + 1)
      
          def devide(self, n: int) -> int:
              return self.catalan(n - 2)
      
      if __name__ == '__main__':
          s = Solution()
          print(s.devide(5))
      
总结
  • 假设一点固定,于是问题就被分成(之前、之后)两部分(对于划分问题来说是划分完两侧),两边都是独立的子问题,于是对于此固定点的问题可以得到总个数,再累加所有的点的总个数就是答案(这讲的就是卡特兰的递推式)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

椰子奶糖

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

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

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

打赏作者

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

抵扣说明:

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

余额充值