套碗游戏得取碗顺序(二)| 豆包MarsCode AI刷题

80 阅读3分钟

问题描述

小F正在玩一个套碗的游戏,每个碗都有一个编号,从1到n,它们从大到小被套在一根木棍上。小F只能从木棍上取最上面的碗,每次只能取一个。现在我们需要计算总共有多少种取碗的顺序。例如,对于2个碗,取碗的顺序可以是 2 11 2,这两种顺序都是合法的。而对于3个碗,给定顺序 3 1 2 不可能通过合法操作实现,因此该顺序不可行。

卡特兰数简介

卡特兰数是一系列自然数,通常出现在组合数学中。第n个卡特兰数可以用以下公式表示:

Cn=n+11(n2n)Cn​=n+11​(n2n​)

也可以用递推公式表示:

Cn=i=0n1CiCn1iCn​=∑i=0n−1​Ci​⋅Cn−1−i​

卡特兰数在很多问题中都有应用,例如:

  • 二叉树的计数:第n个卡特兰数表示有n个节点的不同二叉树的数量。
  • 括号匹配:第n个卡特兰数表示n对括号的所有合法匹配方式。
  • 凸多边形的三角剖分:第n个卡特兰数表示将一个凸多边形分成n-2个三角形的方法数。

问题分析

对于n个碗,合法的取碗顺序数就是第n个卡特兰数。我们可以使用递推公式来计算卡特兰数。具体来说,第n个卡特兰数可以通过以下递推公式计算:

Cn=i=0n1CiCn1iCn​=∑i=0n−1​Ci​⋅Cn−1−i​

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];
}

代码解释

  1. 初始化

    • 如果 n 小于等于 1,直接返回 1,因为只有一个碗或没有碗时,只有一种取法。
    • 创建一个大小为 n + 1 的向量 catalan,用于存储卡特兰数。
    • 初始化 catalan[0] 和 catalan[1] 为 1。
  2. 计算卡特兰数

    • 使用双重循环计算第 i 个卡特兰数。
    • 外层循环从 2 到 n,内层循环从 0 到 i-1
    • 根据递推公式 C_n = \sum_{i=0}^{n-1} C_i \cdot C_{n-1-i} 计算每个卡特兰数。
  3. 返回结果

    • 返回 catalan[n],即第 n 个卡特兰数。

测试用例

  • 测试用例 1

    • 输入:n = 2
    • 输出:2
    • 解释:合法的取碗顺序有 2 1 和 1 2
  • 测试用例 2

    • 输入:n = 3
    • 输出:5
    • 解释:合法的取碗顺序有 3 2 13 1 22 3 12 1 3 和 1 3 2
  • 测试用例 3

    • 输入:n = 4
    • 输出:14
    • 解释:合法的取碗顺序有 14 种。

总结

通过使用卡特兰数,我们可以高效地计算出从1到n的碗的所有合法取碗顺序数。卡特兰数在组合数学中有着广泛的应用,掌握其计算方法不仅可以帮助我们解决类似的问题,还能加深对组合数学的理解。希望本文的详细解释和代码实现能帮助你更好地理解和解决问题。