【问题标题】:How many different rooted unlabelled binary trees have exacly 9 nodes and are left-heavy?有多少个不同的有根无标签二叉树正好有 9 个节点并且是左重的?
【发布时间】:2020-07-28 21:34:36
【问题描述】:

我知道使用第 n 个加泰罗尼亚数字可能有多少棵树,但不知道如何找到左重树。有什么技巧吗?

【问题讨论】:

  • @user3386109 是答案 2333?

标签: algorithm data-structures binary-tree


【解决方案1】:

答案是:2357

我在这里提供了一种合理的方法(不涉及编程)和代码来产生相同的结果,但通过一种更暴力的方法。

A.推理

直观地说,通过排除来计算似乎更容易。所以这导致了这种方法:

  • 计算所有具有 9 个节点的二叉树。正如您已经指出的,这对应于第 9th 加泰罗尼亚数字。这是C9 = 4862
  • 减去根平衡的树的数量,即根的两个子树具有相等的高度(我们将这些子树称为 LR)。这给了我们左重或右重的树的数量。
  • 由于左重树与右重树一样多,因此将此结果除以 2 以获得最终结果。

所以现在我们可以专注于计算第二个要点中提到的数字:

计算在根处严格平衡的树

高度为 2 的树最多有 7 个节点(当它已满时),因此高度至少需要为 3。高度为 5 的树(在根处平衡)至少需要 5 个节点A(在单个路径上),B 中的 5 个(也在单个路径上),所以高度不能超过 4。因此我们只有两种可能性:在根中平衡的 9 节点二叉树的高度是 3 或 4。

让我们分别处理这两种情况:

1。当树的高度为3时

在这种情况下,我们有一棵有 4 层的树。让我们分析每个级别:

前两层有 3 个节点:根及其两个子节点。

第三层是可能存在一些变化的第一层:该层有 2 到 4 个节点。让我们一一处理这三种情况:

1.a 第三层有2个节点

这里第三层在L中有一个节点,在R中有一个节点。每个都可以是其父级的左子或右子。所以两边都有两种可能性:2x2 = 4 种可能性。

第四层不可能有变化:剩下的四个节点是第三层两个节点的子节点。

可能性:4

1.b 第三级有3个节点

有 4 种方法可以从第三级的四个可用位置中选择三个位置。 LR 都只能得到一个节点。我们称这个节点为 x

在第四层,我们需要分配剩下的三个节点,使得 LR 至少得到其中一个。这在 x 得到一个或两个孩子时实现。

  • x 有两个子节点时,剩下的另一个节点有 4 个可能的位置。在这里,您可以看到这 4 个浅灰色的位置:

  • x得到一个孩子时,可以是左孩子也可以是右孩子,其余两个节点可以占据四个可用位置(见上图)有 6 种方式:2x6=12。

所以给定第三级的选择,第四级有 4+12=16 种可能的配置。

将此与第三层的可能性结合起来,我们得到 4x16:

可能性:64

1.c 第三级有4个节点

因此第三层已满。第四层剩下的两个节点需要在LR之间分割,所以每个节点有4个可能的位置。这总共给出了 4x4 = 16 种可能性。

可能性:16

2。当树高为4时

当高度为 4 时,结果 LR 每个只有一个叶子:它们是每个有 4 个节点的 。这是使根严格平衡获得高度4的唯一方法。

L 的根节点没有选择(它是根的左孩子),但是从那里开始,L 中的每个下一个后代都可以其父级的左子或右子。 L 的形状因此有 23 种可能性 = 8。考虑到 R 的形状相同,我们总共有 8x8 = 64 种形状。

可能性:64

总计

综合以上所有因素,我们有 4+64+16 + 64 = 148 种可能的形状,可以得到具有平衡根的树。

因此,应用顶部列出的方法,具有 9 个未标记节点的左重二叉树的总数为 (4862-148)/2 = 2357

B.代码

为了使这成为一个编程挑战,这里是一个 JavaScript 实现,它定义了以下函数:

  • countTreesUpToHeight(n, height):计算所有具有 n 个节点且不高于 的二叉树。使用递归。

  • countTreesWithHeight(n, height):计算所有具有 n 个节点且具有 恰好 给定高度的二叉树。使用前面的函数。

  • countLeftHeavy(n):主函数。使用其他两个函数计算根的左子树高于右子树的所有组合。

所以这种方法不像上面的排除方法。它实际上计算了感兴趣的组合。输出是一样的。

function countTreesUpToHeight(n, height) {
    if (n > 2**(height+1) - 1) return 0; // too many nodes to fit within height
    if (n < 2) return 1;
    let count = 0;
    for (let i = 0; i < n; i++) {
        count += countTreesUpToHeight(i, height-1) 
               * countTreesUpToHeight(n-1-i, height-1);
    }
    return count;
}

function countTreesWithHeight(n, height) {
    return countTreesUpToHeight(n, height) - countTreesUpToHeight(n, height-1);
}

function countLeftHeavy(n) {
    let count = 0;
    // make choices for the height of the left subtree
    for (let height = 0; height < n; height++) {
        // make choices for the number of nodes in the left subtree
        for (let i = 0; i < n; i++) {
            // multiply the number of combinations for the left subtree 
            //   with those for the right subtree 
            count += countTreesWithHeight(i, height-1)
                   * countTreesUpToHeight(n-1-i, height-2);
        }
    }
    return count;
}

let result = countLeftHeavy(9);
console.log(result);               // 2357

【讨论】:

  • 非常感谢您提供解决方案。它对我在这类问题上的思考有很大帮助。如果你不介意,你能用一个例子解释一下1.b吗?我对那部分有点困惑。
  • 我插入了一个带有 1.b 示例的图像
  • 感谢分享。我只是想知道使用 @user3386109 的技术我得到 2333 作为答案,该方法似乎是正确的。但不知道哪个答案/方法是正确的。
  • @Romil 我的评论和这个答案之间的差异是由于“左重”的定义不同。谷歌搜索“左重”支持 trincot 的定义,这就是我删除评论的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-17
  • 2015-01-05
  • 2014-12-12
  • 2010-12-09
  • 2014-03-22
  • 2023-03-14
相关资源
最近更新 更多