一、先了解两个数学概念
在了解卡特兰数之前,需要了解两个数学概念:
1、组合计算公式
c(m,n) = m!/(n! * (m-n)!)
2、两个集合相等的判断
如果集合A有一个公式,可以一一对应到集合B,而集合B也有一个公式一定可以一一映射到集合A,那么A集合和B集合相等。
比如如果国家集合和国旗集合,如果国家列表中每个国家都能找到国旗列表对应的国旗,而国旗列表中总能在国家列表中找到对应的国家,那么我们说国旗列表和国家列表的数量一样
二、卡特兰数介绍
卡特兰数又称卡塔兰数,
number,是组合数学中一个常出现在各种计数问题中出现的数列。其前几项为:
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, …
k(0) = 1, k(1) = 1时,如果接下来的项满足:
k(n) = k(0) * k(n - 1) + k(1) * k(n - 2) + … + k(n - 2) * k(1) + k(n - 1) * k(0)
或者
k(n) = c(2n, n) - c(2n, n-1)
或者
k(n) = c(2n, n) / (n + 1)
就说这个表达式,满足卡特兰数
三、实际题目解决:
假设给你N个0,和N个1,你必须用全部数字拼序列
返回有多少个序列满足:任何前缀串,1的数量都不少于0的数量。
这道题其实就是左括号和有括号合法的问题,一共的排列有c(2n,n)中,减去不合理的前缀串c(2n, n + 1)种
这里就是用到集合相等的概念,我们要找到不合法的串的数量,也就是可以找到多少前缀串中1的数量小于0的数量这个数量等价于在一个集合中有n+1个0,n - 1个1的组合的总数量,也就是c(2n, n+1)。
java代码如下:
public static long ways2(int n) {
if (n == 0 || n == 1) {
return 1;
}
long a = 1;
long b = 1;
int limit = n << 1;
for (int i = 1; i <= limit; i ++) {
if (i <= n) {
a = a * i;
} else {
b = b * i;
}
}
return (b / a)/(n+1);
}
四、类似的题目
类似的问题还有:
- n个左括号,n个右括号,如何排列,才是符合正常的(任何前缀串,(的数量都不少于)的数量)
- 股票n次涨,n次跌,有多少种排列,不会有跌破当前值的时候
- 进出栈:n次进栈,n次出栈,有多少种合理的方式
- 二叉树的排列问题:有N个二叉树节点,每个节点彼此之间无任何差别,返回由N个二叉树节点,组成的不同结构数量是多少?
教授老师:左程云