【发布时间】:2020-07-28 21:34:36
【问题描述】:
我知道使用第 n 个加泰罗尼亚数字可能有多少棵树,但不知道如何找到左重树。有什么技巧吗?
【问题讨论】:
-
@user3386109 是答案 2333?
标签: algorithm data-structures binary-tree
我知道使用第 n 个加泰罗尼亚数字可能有多少棵树,但不知道如何找到左重树。有什么技巧吗?
【问题讨论】:
标签: algorithm data-structures binary-tree
答案是:2357
我在这里提供了一种合理的方法(不涉及编程)和代码来产生相同的结果,但通过一种更暴力的方法。
直观地说,通过排除来计算似乎更容易。所以这导致了这种方法:
所以现在我们可以专注于计算第二个要点中提到的数字:
高度为 2 的树最多有 7 个节点(当它已满时),因此高度至少需要为 3。高度为 5 的树(在根处平衡)至少需要 5 个节点A(在单个路径上),和在 B 中的 5 个(也在单个路径上),所以高度不能超过 4。因此我们只有两种可能性:在根中平衡的 9 节点二叉树的高度是 3 或 4。
让我们分别处理这两种情况:
在这种情况下,我们有一棵有 4 层的树。让我们分析每个级别:
前两层有 3 个节点:根及其两个子节点。
第三层是可能存在一些变化的第一层:该层有 2 到 4 个节点。让我们一一处理这三种情况:
这里第三层在L中有一个节点,在R中有一个节点。每个都可以是其父级的左子或右子。所以两边都有两种可能性:2x2 = 4 种可能性。
第四层不可能有变化:剩下的四个节点是第三层两个节点的子节点。
可能性:4
有 4 种方法可以从第三级的四个可用位置中选择三个位置。 L 或 R 都只能得到一个节点。我们称这个节点为 x。
在第四层,我们需要分配剩下的三个节点,使得 L 和 R 至少得到其中一个。这在 x 得到一个或两个孩子时实现。
当x得到一个孩子时,可以是左孩子也可以是右孩子,其余两个节点可以占据四个可用位置(见上图)有 6 种方式:2x6=12。
所以给定第三级的选择,第四级有 4+12=16 种可能的配置。
将此与第三层的可能性结合起来,我们得到 4x16:
可能性:64
因此第三层已满。第四层剩下的两个节点需要在L和R之间分割,所以每个节点有4个可能的位置。这总共给出了 4x4 = 16 种可能性。
可能性:16
当高度为 4 时,结果 L 和 R 每个只有一个叶子:它们是每个有 4 个节点的 链。这是使根严格平衡和获得高度4的唯一方法。
L 的根节点没有选择(它是根的左孩子),但是从那里开始,L 中的每个下一个后代都可以其父级的左子或右子。 L 的形状因此有 23 种可能性 = 8。考虑到 R 的形状相同,我们总共有 8x8 = 64 种形状。
可能性:64
综合以上所有因素,我们有 4+64+16 + 64 = 148 种可能的形状,可以得到具有平衡根的树。
因此,应用顶部列出的方法,具有 9 个未标记节点的左重二叉树的总数为 (4862-148)/2 = 2357
为了使这成为一个编程挑战,这里是一个 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
【讨论】: