卡特兰(Catalan)数入门详解

article/2025/11/7 10:07:10

文章目录

  • 基本概念
    • 介绍
    • 定义
  • 实际问题
    • 例题1
    • 方法
    • 01序列
    • 括号匹配
    • 进出栈问题
    • 312排列
    • 不相交弦问题
    • 二叉树的构成问题
    • 凸多边形的三角划分
    • 阶梯的矩形划分

也许更好的阅读体验

基本概念

介绍

学卡特兰数我觉得可能比组合数要难一点,因为组合数可以很明确的告诉你那个公式是在干什么,而卡特兰数却像是在用大量例子来解释什么时卡特兰数
这里,我对卡特兰数做一点自己的理解
卡特兰数是一个在组合数学里经常出现的一个数列,它并没有一个具体的意义,却是一个十分常见的数学规律

对卡特兰数的初步理解:有一些操作,这些操作有着一定的限制,如一种操作数不能超过另外一种操作数,或者两种操作不能有交集等,这些操作的合法操作顺序的数量

为了区分组合数,这里用 f n f_n fn表示卡特兰数的第 n n n
从零开始,卡特兰数的前几项为 1 , 1 , 2 , 5 , 14 , 42 , 132 , 429 , 1430 , 4862 , 16796 , 58786 , 208012 , 742900 , 2674440 , 9694845 , 35357670 , 129644790 … 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790\ldots 1,1,2,5,14,42,132,429,1430,4862,16796,58786,208012,742900,2674440,9694845,35357670,129644790

定义

递归定义

f n = f 0 ∗ f n − 1 + f 1 ∗ f n − 2 + … + f n − 1 f 0 f_n=f_0*f_{n-1}+f_1*f{n-2}+\ldots+f_{n-1}f_{0} fn=f0fn1+f1fn2++fn1f0,其中 n ≥ 2 n\geq 2 n2

递推关系

f n = 4 n − 2 n + 1 f n − 1 f_n=\frac{4n-2}{n+1}f_{n-1} fn=n+14n2fn1

通项公式

f n = 1 n + 1 C 2 n n f_n=\frac{1}{n+1}C_{2n}^{n} fn=n+11C2nn

经化简后可得

f n = C 2 n n − C 2 n n − 1 f_n=C_{2n}^{n}-C_{2n}^{n-1} fn=C2nnC2nn1

只要我们在解决问题时得到了上面的一个关系,那么你就已经解决了这个问题,因为他们都是卡特兰数列


实际问题

先用一个最经典的问题来帮助理解卡特兰数
去掉了所有的掩饰,将问题直接写出来就是

例题1

在一个 w × h w\times h w×h的网格上,你最开始在 ( 0 , 0 ) \left(0,0\right) (0,0)上,你每个单位时间可以向上走一格,或者向右走一格,在任意一个时刻,你往右走的次数都不能少于往上走的次数,问走到 ( n , n ) , 0 ≤ n \left(n,n\right),0\leq n (n,n),0n有多少种不同的合法路径。

合法路径个数为 C 2 n n − C 2 n n − 1 C_{2n}^{n}-C_{2n}^{n-1} C2nnC2nn1

直接求不好,考虑求有多少种不合法路径
路径总数为在 2 n 2n 2n次移动中选 n n n次向上移动,即 C 2 n n C_{2n}^{n} C2nn

画一下图,我们把 y = x + 1 y=x+1 y=x+1这条线画出来,发现所有的合法路径都是不能碰到这条线的,碰到即说明是一条不合法路径
先随便画一条碰到这条线的不合法路径,所有的不合法路径都会与这条线有至少一个交点,我们把第一个交点设为 ( a , a + 1 ) \left(a,a+1\right) (a,a+1)
如图

p1.png

我们把 ( a , a + 1 ) \left(a,a+1\right) (a,a+1)之后的路径全部按照 y = x + 1 y=x+1 y=x+1这条线对称过去
这样,最后的终点就会变成 ( n − 1 , n + 1 ) \left(n-1,n+1\right) (n1,n+1)
p2.png

由于所有的不合法路径一定会与 y = x + 1 y=x+1 y=x+1有这么一个交点
我们可以得出,所有不合法路径对称后都唯一对应着一条到 ( n − 1 , n + 1 ) \left(n-1,n+1\right) (n1,n+1)的路径
且所有到 ( n − 1 , n + 1 ) \left(n-1,n+1\right) (n1,n+1)的一条路径都唯一对应着一条不合法路径(只需将其对称回去即可)
所以不合法路径总数是 C 2 n n − 1 C_{2n}^{n-1} C2nn1

那么合法的路径总数为 C 2 n n − C 2 n n − 1 C_{2n}^{n}-C_{2n}^{n-1} C2nnC2nn1

这是一个非常好用且重要的一个方法,其它的问题也可以用该方法解决
找到不合法路径唯一对应的到另一个点的路径
如网格计数


方法

先将方法写在前面吧
相信大家都听过烧开水这个数学小故事吧
和学习数学一样,转化是基本思路,将一个问题转化为另外一个已经解决了的问题是最重要的


01序列

你现在有 n n n 0 0 0 n n n 1 1 1,问有多少个长度为 2 n 2n 2n的序列,使得序列的任意一个前缀中 1 1 1的个数都大于等于 0 0 0的个数
例如 n = 2 n=2 n=2
1100 , 1010 1100,1010 1100,1010两种合法序列
1001 , 0101 , 0110 , 0011 1001,0101,0110,0011 1001,0101,0110,0011都是不合法的序列

合法的序列个数为 C 2 n n − C 2 n n − 1 C_{2n}^{n}-C_{2n}^{n-1} C2nnC2nn1

我们把出现一个 1 1 1看做向右走一格,出现一个 0 0 0看做向上走一格,那么这个问题就和上面的例题 1 1 1一模一样了

拓展
如果是 n n n 1 , m 1,m 1,m 0 0 0呢?
不过是最后的终点变为了 ( n , m ) \left(n,m\right) (n,m)罢了
如果是 1 1 1的个数不能够比 m m m k k k
我们只需将 y = x + 1 y=x+1 y=x+1这条线上下移动即可


括号匹配

你有 n n n个左括号, n n n个右括号,问有多少个长度为 2 n 2n 2n的括号序列使得所有的括号都是合法的

合法的序列个数为 C 2 n n − C 2 n n − 1 C_{2n}^{n}-C_{2n}^{n-1} C2nnC2nn1

要使所有的括号合法,实际上就是在每一个前缀中左括号的数量都不少于右括号的数量
将左括号看做 1 1 1,右括号看做 0 0 0,这题又和上面那题一模一样了


进出栈问题

有一个栈,我们有 2 n 2n 2n次操作, n n n次进栈, n n n次出栈,问有多少中合法的进出栈序列

合法的序列个数为 C 2 n n − C 2 n n − 1 C_{2n}^{n}-C_{2n}^{n-1} C2nnC2nn1

要使序列合法,在任何一个前缀中进栈次数都不能少于出栈次数 … \ldots
后面就不用我说了吧,和上面的问题又是一模一样的了


312排列

一个长度为 n n n的排列 a a a,只要满足 i < j < k i<j<k i<j<k a j < a k < a i a_j<a_k<a_i aj<ak<ai就称这个排列为 312 312 312排列
n n n的全排列中不是 312 312 312排列的排列个数

答案也是卡特兰数

我们考虑 312 312 312排列有什么样的特征
如果考虑一个排列能否被 1 , 2 , 3 , … , n − 1 , n 1,2,3,\ldots,n-1,n 1,2,3,,n1,n排列用进栈出栈来表示
那么 312 312 312排列就是所有不能被表示出来的排列
那么这个问题就被转化成进出栈问题了


不相交弦问题

在一个圆周上分布着 2 n 2n 2n个点,两两配对,并在这两个点之间连一条弦,要求所得的 2 n 2n 2n条弦彼此不相交的配对方案数
n = 4 n=4 n=4时,一种合法的配对方案为如图

p3.png

合法的序列个数为 C 2 n n − C 2 n n − 1 C_{2n}^{n}-C_{2n}^{n-1} C2nnC2nn1

这个问题没有上面的问题那么显然,我们规定一个点为初始点,然后规定一个方向为正方向
如规定最上面那个点为初始点,逆时针方向为正方向
然后我们把一个匹配第一次遇到的点(称为起点)旁边写一个左括号 ( ( (,一个匹配第二次遇到的点(称为终点)旁边写一个右括号 ) ) )
如图

p4.png

看出来吗,在规定了这样的一个顺序后,在任意一个前缀中起点的个数都不能少于终点的个数
于是这又是一个卡特兰数列了


二叉树的构成问题

n n n个点,问用这 n n n个点最终能构成多少二叉树

答案仍然是卡特兰数列

这个问题不是用上面的方法,是用递归定义的卡特兰数

一个二叉树分为根节点,左子树,右子树
其中左子树和右子树也是二叉树,左右子树节点个数加起来等于 n − 1 n-1 n1
i i i个点能构成 f i f_i fi个二叉树
我们枚举左子树有几个点可得
f n = f 0 ∗ f n − 1 + f 1 ∗ f n − 2 + … + f n − 1 ∗ f 0 f_n=f_0*f_{n-1}+f_{1}*f_{n-2}+\ldots+f_{n-1}*f_{0} fn=f0fn1+f1fn2++fn1f0
这个和卡特兰数列的递归定义是一模一样的


凸多边形的三角划分

一个凸的 n n n边形,用直线连接他的两个顶点使之分成多个三角形,每条直线不能相交,问一共有多少种划分方案

答案还是卡特兰数列

我们在凸多边形中随便挑两个顶点连一条边,这个凸多边形就会被分成两个小凸多边形,由于每条直线不能相交,接下来我们就只要求这两个小凸多边形的划分方案然后乘起来即可

和二叉树的构成问题一样,我们枚举大凸多边形被分成的两个小凸多边形的大小即可


阶梯的矩形划分

一个阶梯可以被若干个矩形拼出来
图示是两种划分方式

p5.png
p6.png

像下图是不合法的划分方式
p7.png

问,一个 n n n阶矩形有多少种矩形划分

答案仍然是卡特兰数列

我们考虑阶梯的每个角

如图
p8.png

每个角一定是属于不同的矩形的,我们考虑和左下角属于一个矩形的是哪个角
这个矩形将这个梯形又分成两个小梯形,如图

p9.png

于是我们又可以写出递推式了
和卡特兰数列的递归式是一样的

卡特兰数就讲这么多吧

如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧


http://chatgpt.dhexx.cn/article/I9XCeg9e.shtml

相关文章

Catalan数

Catalan&#xff08;卡特兰&#xff09;数 卡特兰数&#xff0c;又称卡塔兰数&#xff0c;是组合数学中一种常出现于各种计数问题中的数列。以比利时的数学家欧仁查理卡塔兰 (1814–1894)的名字来命名。1730年左右被蒙古族数学家明安图 (1692-1763)使用于对三角函数幂级数的推导…

服务端程序的keeplive

查看更多 https://www.yuque.com/docs/share/045e7b34-8b67-408f-bdac-11a2e8645342

LVS和Keeplive

文章目录 一、Keepalived 概述1. 为什么需要 keepalived2. keepalived 是什么3. keepalived 服务重要功能4. keepalived 高可用故障切换转移原理5. keepalived 体系主要模块及其作用6. 使用 keepalived 实现双机热备 二、LVS DR Keepalived 高可用集群构建1. 集群概述3. 案例…

RabbitMQ-KeepLive

文章目录 1. KeepLive基础知识2. KeepLive安装3. KeepLive主节点配置4. KeepLive从节点配置5. 执行脚本 1. KeepLive基础知识 基础概述 三大特性 高可用原理 2. KeepLive安装 3. KeepLive主节点配置 4. KeepLive从节点配置 5. 执行脚本 VIP的漂移&#xff1a;使用了同一…

list列表跳转保存位置,返回列表刷新keeplive

vue页面路由跳转离开时保存滚动条位置&#xff0c;进入该页面是获取位置 beforeRouteLeave (to, from, next) {const position document.documentElement.scrollTopsessionStorage.setItem(scrollTop, JSON.stringify(position))next()},// // 进入该页面时&#xff0c;用之…

keeplive+haproxy+nginx

Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器&#xff0c;也是一个 IMAP/POP3/SMTP 代理服务器。 Nginx 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的&#xff0c;第一个公开版本0.1.0发布于2004年10月4日。其将源代码以类BSD许可证…

keeplive发生脑裂问题处理过程

某上云项目中,k8s管理节点vip突然时不时无法访问了&#xff0c;针对这个问题&#xff0c;首先对vip发起了一个长ping;发现过一会就ping不通了&#xff0c;结果如下&#xff1a; 然后查看keeplive的日志&#xff0c;两台主机会发生vip会时不时的争抢&#xff1a; 因为我们在这两…

vue单页面html缓存问题,vue单页面 回退页面 keeplive 缓存问题

场景&#xff1a;项目中遇到 vue 点击回退 从A页跳到B页&#xff0c;缓存A页&#xff0c;当B页状态修改再次返回A时&#xff0c;A页查询条件缓存不刷新&#xff0c;列表刷新 A页&#xff1a; B页&#xff1a; html 解决方法&#xff1a; 利用keep-alive 缓存须要缓存的页面 1.…

Vue生命周期和钩子函数及使用keeplive缓存页面不重新加载

Vue生命周期 每个Vue实例在被创建之前都要经过一系列的初始化过程&#xff0c;这个过程就是vue的生命周期&#xff0c;在这个过程中会有一些钩子函数会得到回调 Vue中能够被网页直接使用的最小单位就是组件&#xff0c;我们经常写的&#xff1a; var vm new Vue({el: #app,...…

LVS(三)lvs+keeplive

一 场景引入1 我们知道LVS仅仅是做根据调度算法和策略来做负载均衡的&#xff0c;LVS本身只是调度后端服务器&#xff0c;并不管后端服务器的死活&#xff0c;想想这样一个场景&#xff1a;如果由于由于某种原因&#xff0c;后端服务器挂掉&#xff0c;而调度服务器却不知道&am…

lvs+keeplive

Keepalived概述 调度出现单点故障&#xff0c;如何解决&#xff1f;Keepalived实现了高可用集群Keeepalived最初是为LVS设计的&#xff0c;专门监控各服务器节点状态Keepalived后来加入了VRRP功能&#xff0c;防止单点故障 Keepalived运行原理 Keepalived检测每个服务器节点…

使用keeplive处理socket网络异常断开

网络异常断开原因主要有那些呢&#xff1f;归纳起来主要有以下两种&#xff1a; 1、客户端程序异常。 对于这种情况&#xff0c;我们很好处理&#xff0c;因为客户端程序异常退出会在服务端引发ConnectionReset的Socket异常&#xff08;就是WinSock2中的10054异常&#xff09;。…

mysql mm keeplive_mysql +keeplive

下载tar包 ./configure --prefix/usr/local/keepalived --with-kernel-dir/usr/src/kernels/2.6.32-431.el6.x86_64/ \ 注意加内核 &&make && make install cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/ cp /usr/local/keepalived…

解决keep-live使用之后的问题

keep-aliv能够帮助我们实现页面ajax请求只被请求一次&#xff0c;在你跳转页面的时候&#xff0c;也不会被请求多次&#xff0c;可是比如在旅游页面中&#xff0c;当我们在城市选择页面重新选择城市&#xff0c;这个时候就需要重新发送一个ajax请求&#xff0c;来显示对应城市的…

nginx和keeplive实现负载均衡高可用

一、 Keeplive服务介绍 Keeplive期初是专门为LVS设计的&#xff0c;专门用来监控LVS集群系统中各个服务节点的状态&#xff0c;后来又加入VRRP的功能&#xff0c;因此除了配合LVS服务以外&#xff0c;也可以作为其他服务&#xff08;nginx&#xff0c;haroxy&#xff09;的高可…

php用Ajax传递数组

代码如下: 定义array数组 var array [1,2,3];$.ajax({url:"cart.php?actdelcart",async:false,type:POST,data:{array:array},dataType:json,traditional: true,success:function(data){alert(data)},error:function(){alert("#");}}); 当我们用ajax传递…

【JQuery】Ajax 参数为数组 的方法

背景介绍 前端页面为HTML&#xff0c; 后端为Spring html中根据多选框的值&#xff0c;使用ajax请求接口动态加载其他元素的选项值。 代码 // select 下拉多选框的值var idCardType $("#idCardType").val();// [2075, 2077, 2078]$.ajax({url : url,type : "…

使用ajax传递数组和后台接收

使用ajax异步的提交多选框得到需要操作的对象的id&#xff0c;这时我们可以把每一个id做出一个对象&#xff0c;之后放到一个数组中&#xff0c;再使用JSON.stringify()对这个数组进行json的格式化&#xff1b;在后台中再inputStream中解析出我们的json字符串&#xff0c;之后只…

ajax传数组,后端接收数组

ajax内容 使用JSON.stringify(&#xff09;将数组转换为JSON字符串 //发送ajax将数组发送给handler$.ajax({url:"admin/batch/remove.json", //服务器接收请求的URL地址type:"post", //设置请求方式postcontentType:"application/json;charsetUTF-8&…

教你怎么用ajax传数组(也可以是转为json)

我之前写过一个关于ajax的详解&#xff0c;那个是标准的ajax&#xff0c;今天介绍的是怎么用ajax传递数组这样的数据类型呢&#xff1f;很多的时候我们需要给后端的数据不是几个单独的数据&#xff0c;一般见到的代码的是这样的&#xff1a; data: { id : id, name : name, se…