卡特兰数基本理解
图片来自https://www.cnblogs.com/linzhengmin/p/11298140.html(大神的博客)
代码转自百度知道(侵删致歉)
背景(可自行跳过,俺也就是为了撑点篇幅)
卡特兰数又称卡塔兰数,卡特兰数是组合数学中一种常出现于各种计数问题中的数列。以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)的名字来命名。
简介(俺觉得这个还挺重要的,你大概得知道这是个什么东西吧)
卡特兰数又称卡塔兰数,Catalan number是组合数学中一个常出现于各种计数问题中的数列。以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)的名字来命名,(伟大的数学家的名字还是得名垂青史哈)。
其前几项为(从第零项开始) : 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
相信大家通过这些数字已经看出来规律了吧,反正我是没有。
…………
那我们从根本出发哈
卡特兰数的定义——是一种出现于各种计数问题中的数列。
所以卡塔兰数更贴切的叫法是卡特兰数列(个人觉得哈),也就是说有很多计数问题中,最后得到的数列能满足卡特兰数列的这样一个规律。
这里的各种计数问题是什么呢,啊对我一开始看着也很懵逼的,就算把一些满足的情况列出来有用吗,爷不可能全部记下来吧。
啊这,所以,先体会一些卡特里数列适用的例子,找一下感觉,大概有个轮廓。
各种例子(体会一下卡特兰数列是什么感觉)emmmm,应该可以跳过吧。
寻找路径走法
像这样
问你从A走到B问有多少种走法
显然可以看出当格子越多的时候走法也越多
而这个n对应的走法正好就是服从卡塔兰数列的。
括号匹配
我都写了就不打字了
其实大同小异,跟上面的例子其实是一个意思
左括号和右括号分别对应像上走和像右走
出入栈后的字符串
比如一串字符串
问你入栈出栈之后的顺序
大概的结论
从上面的三种例子来看
我个人理解为
有两种选择,并且分别给定两种选择的次数,将这所有的情况进行组合。为什么不是排列呢,emmmm
就拿上面的点格图说
我们从一个端点到另一个端点一定要走2n步,我们给这2n步都编号,那一定有n步是在向右,另外的在向上。
为什么不是排列,我的理解是这里已经排好了,1-2n,就是一个顺序序列,而你要做的,就是在这个顺序序列里选择n个作为一个方向。
当然这只是解释了普通的一个走图问题。
显然是不符合卡特兰数列的。
卡特兰数列的模型则是对其增加了限制
寻找路径走法中,不能走上半部分,只留下一个三角形的区域走。
这就增加了限制。
又或许向括号匹配问题
不可能第一个括号就是右括号(当然还有其他限制条件)
或者是出入栈问题中
不可能一开始的操作就是出栈(即空栈情况下出栈)
然后发现对于类似的问题都可以套用寻找路径的模型,值观好理解。
推出规律
那如何推出规律呢
定义式是这样的
那为什么是这样
用文字来说就是一步步确定
确定0步,后面不确定(自由组合的情况)的就有n步
确定1步,后面不确定的就有n-1步
下面就拿寻找路径开刀
寻找路径
可能不好理解
但对于寻找路径还有另一种理解方法
总路径数 - 错误路径数= 正确路径数
这就是下图的情况了
(这里为了放便把寻找路径的两种理解方法放到一起如果上面的没看懂的可以先看看下面的括号匹配理解上面的思路)
你会发现要只走下半部分就绝对不能接触到绿色那条线,一旦接触就是错误走法。
可以轻易的知道全部走法就是
Cn2n
减去错误走法Cn+12n
代码实现(转自百度)
从第一种路径走法也能看出向下转换n转到n-1,n-1到n-2,不难想到能用递归来解决这个问题。
java代码转自百度知道
import java.util.*;
import java.math.BigInteger;
public class Catalan { //求卡特兰数
public static void main(String[] args){
int numberOfCatalan = 101; //要求多少个卡特兰数
BigInteger[] digis = new BigInteger[numberOfCatalan];
digis = generateCatalan(numberOfCatalan);
Scanner scanner = new Scanner(System.in);
int number;
while(true) {
number = scanner.nextInt();
if(number == -1) {
break;
String answer = digis[number].toString();
System.out.println(answer);
}
}
}
static BigInteger[] generateCatalan(int numberOfCatalan) {
//产生卡特兰数
BigInteger digis[] = new BigInteger[numberOfCatalan + 1];
BigInteger x = new BigInteger("1"); //第一个卡特兰数为1
digis[1] = x;
int y = 0;
int z = 0;
for(int counter = 2; counter <= numberOfCatalan; ++ counter) {
y = 4 * counter - 2;
z = counter + 1;
digis[counter] = digis[counter-1].multiply(new BigInteger("" + y));
digis[counter] = digis[counter].divide(new BigInteger("" + z));
}
return digis;
}
}
//使用递归的方式解决卡特兰数
public static double CatalanNumber(int n) {
if (n == 1) {
return 1;
} else {
return CatalanNumber(n - 1) * 2 * (2 * n - 1) / (n + 1);
}
}
public static void main(String[] args) {
for (int i = 1; i <= 50; i++) {
System.out.println(i + "'s Catalan Number is " + CatalanNumber(i));
}
}