问题描述
小F正在玩一个套碗的游戏,每个碗都有一个编号,从1到n,它们从大到小被套在一根木棍上。小F只能从木棍上取最上面的碗,每次只能取一个。现在我们需要计算总共有多少种取碗的顺序。例如,对于2个碗,取碗的顺序可以是 2 1 或 1 2,这两种顺序都是合法的。而对于3个碗,给定顺序 3 1 2 不可能通过合法操作实现,因此该顺序不可行。
卡特兰数简介
卡特兰数是一系列自然数,通常出现在组合数学中。第n个卡特兰数可以用以下公式表示:
也可以用递推公式表示:
卡特兰数在很多问题中都有应用,例如:
- 二叉树的计数:第n个卡特兰数表示有n个节点的不同二叉树的数量。
- 括号匹配:第n个卡特兰数表示n对括号的所有合法匹配方式。
- 凸多边形的三角剖分:第n个卡特兰数表示将一个凸多边形分成n-2个三角形的方法数。
问题分析
对于n个碗,合法的取碗顺序数就是第n个卡特兰数。我们可以使用递推公式来计算卡特兰数。具体来说,第n个卡特兰数可以通过以下递推公式计算:
long long solution(int n) {
if (n <= 1) {
return 1;
}
vector<long long> catalan(n + 1, 0);
catalan[0] = 1;
catalan[1] = 1;
for (int i = 2; i <= n; ++i) {
for (int j = 0; j < i; ++j) {
catalan[i] += catalan[j] * catalan[i - j - 1];
}
}
return catalan[n];
}
代码解释
-
初始化:
- 如果
n小于等于 1,直接返回 1,因为只有一个碗或没有碗时,只有一种取法。 - 创建一个大小为
n + 1的向量catalan,用于存储卡特兰数。 - 初始化
catalan[0]和catalan[1]为 1。
- 如果
-
计算卡特兰数:
- 使用双重循环计算第
i个卡特兰数。 - 外层循环从 2 到
n,内层循环从 0 到i-1。 - 根据递推公式
C_n = \sum_{i=0}^{n-1} C_i \cdot C_{n-1-i}计算每个卡特兰数。
- 使用双重循环计算第
-
返回结果:
- 返回
catalan[n],即第n个卡特兰数。
- 返回
测试用例
-
测试用例 1:
- 输入:
n = 2 - 输出:
2 - 解释:合法的取碗顺序有
2 1和1 2。
- 输入:
-
测试用例 2:
- 输入:
n = 3 - 输出:
5 - 解释:合法的取碗顺序有
3 2 1、3 1 2、2 3 1、2 1 3和1 3 2。
- 输入:
-
测试用例 3:
- 输入:
n = 4 - 输出:
14 - 解释:合法的取碗顺序有 14 种。
- 输入:
总结
通过使用卡特兰数,我们可以高效地计算出从1到n的碗的所有合法取碗顺序数。卡特兰数在组合数学中有着广泛的应用,掌握其计算方法不仅可以帮助我们解决类似的问题,还能加深对组合数学的理解。希望本文的详细解释和代码实现能帮助你更好地理解和解决问题。