【LeetCode】222. 完全二叉树的节点个数

leetcode

 

📊 解题思路

完全二叉树的特性(最后一层节点靠左排列)可优化节点计数:

  1. ​​高度计算​​:计算左右子树的最左路径深度(高度)
  2. ​​满二叉树判定​​:
    • 左子树高度 = 右子树高度 → 左子树为满二叉树
    • 左子树高度 > 右子树高度 → 右子树为满二叉树
  3. ​​公式优化​​:满子树直接通过公式 2^h - 1 计算节点数,避免递归遍历

时间复杂度从普通遍历的 ​​O(n)​​ 优化至 ​​O(log²n)​​

🧩 关键步骤

  1. ​​终止条件​​:节点为空时返回0
  2. ​​高度计算​​:
    • 左子树高度:从根节点一直向左遍历的深度
    • 右子树高度:从根节点一直向左遍历的深度(非向右
  3. ​​分支决策​​:

💻 代码实现

func countNodes(root *TreeNode) int {
    if root == nil {
        return 0
    }
    leftHeight := getHeight(root.Left)
    rightHeight := getHeight(root.Right)

    if leftHeight == rightHeight {
        return (1 << leftHeight) + countNodes(root.Right)
    }
    return (1 << rightHeight) + countNodes(root.Left)
}

// 辅助函数:向左遍历计算高度
func getHeight(node *TreeNode) int {
    height := 0
    for node != nil {
        height++
        node = node.Left
    }
    return height
}

🔍 代码解析

  1. ​​getHeight函数​​:
    • 沿左子树遍历至叶子节点
    • 返回路径长度(例:节点2在示例1中高度=2)
  2. ​​主逻辑​​:
    • ​​计算左右子树高度(均向左遍历)
    • 高度相等时,左子树满
      • (1 << leftHeight) 计算左子树+根节点数(公式:2ʰ)
      • 递归计算右子树节点
    • ​​第17行​​:高度不等时,右子树满
      • (1 << rightHeight) 计算右子树+根节点数
      • 递归计算左子树节点

✅ 示例测试

func main() {
    root1 := &TreeNode{Val: 1}
    root1.Left = &TreeNode{Val: 2}
    root1.Right = &TreeNode{Val: 3}
    root1.Left.Left = &TreeNode{Val: 4}
    root1.Left.Right = &TreeNode{Val: 5}
    root1.Right.Left = &TreeNode{Val: 6}
    fmt.Println(countNodes(root1)) // 6

    fmt.Println(countNodes(nil)) // 0

    root3 := &TreeNode{Val: 1}
    fmt.Println(countNodes(root3)) // 1
}

⏱ 复杂度分析

指标普通遍历优化算法
时间复杂度 O(n) ​​O(log²n)​​
空间复杂度 O(log n) O(log n)

​​推导过程​​:

  • 单次递归:高度计算耗时 O(log n)
  • 递归深度:树高 O(log n)
  • 总耗时:O(log n) × O(log n) = O(log²n)
posted @ 2025-06-06 19:16  云隙之间  阅读(31)  评论(0)    收藏  举报