题目描述:12 个高矮不同的人,排成两排,每排必须是从矮到高排列,而且第二排比对应的第一排的人高,问排列方式有多少种?
本文将基于两个「等价问题」,逐步推导至「卡特兰数」
等价问题一
- 由 6 个 0 和 6 个 1 组成一个 12 位的二进制数,要求从左到右扫描,使得任意位置 0 的累计数都不小于 1 的累计数,求满足条件的组合有多少种。
【证明】
将12个人以 A, B, C, … F, L从低到高标记。并将第一排位置标为 0,第二排位置标为 1。如下图:
以 A - L 的顺序开始选择位置,根据选择顺序,得到一个由 6 个 0 和 6 个 1 组成的二进制数。不难发现,为了满足「每排必须是从矮到高排列, 而且第二排比对应的第一排的人高」,生成的二进制数在任意位置 0 的累计数都必须大于或等于 1 的累计数
基于此将问题转换为「等价问题一」:由 6 个 0 和 6 个 1 组成一个 12 位的二进制数,要求从左到右扫描,使得任意位置 0 的累计数都不小于 1 的累计数,求满足条件的组合有多少种
等价问题二
- 6 个元素进出栈(一次),问不同的出栈顺序有几种?
基于「等价问题一」,我们得到了一个 12 位的二进制数。其中 6 个 0 和 6 个 1,且在任意位置 0 的累计数不小于 1 的累计数。
0 当做「入栈」,1 当做「出栈」。「0 的累计数在任意位置都不小于 1 的累计数」 好比 「栈内必须有元素才能选择出栈」。
基于此将问题转换为「等价问题二」:6 个元素进出栈(一次),问不同的出栈顺序有几种?
解题思路
基于「等价问题二」,先将问题设为:
- 有 n 个元素进出栈,问不同的出栈顺序有几种?
设函数 h(n) 为 n 个元素进出栈顺序的解。假设 k (1 <= k <= n) 是最后一个出栈的元素,那么 k 进栈之前栈一定是空的,k 之前的 (k - 1) 个元素的进出栈是独立的 即 h(k - 1)。同理 k 之后的 (h - k) 个元素也是独立的 即 h(n - k)。 根据前后结果,求得当 k 最后一个出栈时结果为:h(k - 1) * h(n - k)。
因为 k 可以是 [1, n] 之间的任意数,所以 h(n) 是累加 k 为 1 - n 的所有结果。即:
- h(n) = h(0)*h(n-1) + h(1)*h(n-2) + … + h(n-1)*h(0)。
当只有一个元素时,进出栈顺序只有一种。即 h(1) = 1,因为 h(1) = h(0) * h(0),h(0) = 1。
java 代码实现 h(n);将n = 6带入,计算出结果 132。
public static int h(int n){
if(n == 0 || n == 1){
return 1;
}
int ret = 0;
for (int i = 0; i < n; i++){
ret += h(i) * h(n - i -1);
}
return ret;
}
参考:
- https://baike.baidu.com/item/%E5%8D%A1%E7%89%B9%E5%85%B0%E6%95%B0/6125746
- https://blog.youkuaiyun.com/qq_38216239/article/details/78738785