【问题标题】:Time complexity of testing if a binary tree is balanced测试二叉树是否平衡的时间复杂度
【发布时间】:2020-03-18 03:03:32
【问题描述】:

下面的代码测试二叉树是否平衡。我被告知它的运行时间是 O(n log n)。

据我了解...

  • getHeight()每个节点都访问一次,所以是O(n)。

  • isBalanced() 调用getHeight().. 然后递归

如果在所有n个节点上调用isBalanced(),它调用getHeight()是O(n),为什么复杂度不是O(n²)?

int getHeight(TreeNode root) {
    if (root == null) return -1; 
    return Math.max(getHeight(root.left), getHeight(root.right)) + 1;
}

boolean isBalanced(TreeNode root) {
    if (root == null) return true;
    int heightDiff = getHeight(root.left) - getHeight(root.right);
    if (Math.abs(heightDiff) > 1) 
        return false;
    else
        return isBalanced(root.left) && isBalanced(root.right);

}

【问题讨论】:

  • 你说的是真的,但不完整。递归多少次?
  • 递归 isBalanced() 不会访问树中的每个节点吗?
  • 请遍历代码看看
  • 在最坏的情况下,当树平衡时,每个节点都会调用递归方法。

标签: java time-complexity binary-tree


【解决方案1】:

n,你的意思是整个树中的节点数。在这种情况下,getHeight 方法在根节点上调用时只需 O(n)。通常,它是 O(m),其中 m 是您调用 getHeight on 的节点的子树中的节点数;并且这些子树中的大多数都比 n 小很多。这是你困惑的根本原因。

当左右子树的高度相差 2 或更多时,isBalanced 方法会提前返回,无需递归。所以我们只需要计算左右高度最多相差1的节点的递归调用,即子树平衡的节点。在最坏的情况下,所有节点的子树都是平衡的,所以我们永远不会提前停止递归。

鉴于此,让我们假设树平衡的。然后getHeight 每个节点调用一次,运行时间与节点子树的大小成正比。对于大小为 n = 2^k - 1 的平衡树,有:

  • 2^(k-1)个子树大小为1的叶子节点,
  • 2^(k-2) 个大小为 3 的子树,
  • 2^(k-3) 个大小为 7 的子树,
  • ...
  • 2^i 个大小为 2^(k-i) - 1 的子树,
  • ...
  • 2个大小为2^(k-1) - 1的子树,
  • 1 个大小为 2^k - 1 = n 的子树。

这些的总和是 i = 0 到 k-1 的 2^i * (2^(k-i) - 1) 的总和。每一项约为 2^k = n,有 k = log_2 n 项,总复杂度为 n * log_2 n = O(n log n)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多