2021年8月5日
leetcode 222题
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
入门
看到这题, 很容易想到用深搜或广搜求解 ,然而, 同样时间复杂度的递归分治解法更加简单
递归实现, 时间和空间复杂度都是O(n)
func countNodes(root *TreeNode) int {
if root == nil {
return 0
}
return 1 + countNodes(root.Left) + countNodes(root.Right)
}
进阶
我们可以根据完全二叉树的性质发现:
一棵完全二叉树可以这样分为两部分: 最后一层,可能满也可能不满; 除去最后一层的都是满的
但是最后一层的节点数怎么确定,这其实就是一个搜索问题了?
先来想一个问题: 有一个二叉树, 如何判断第 k 个节点是否存在呢?下面是leetcode的题解的一部分
如何判断第 k 个节点是否存在呢?如果第 k 个节点位于第 h 层,则 kk 的二进制表示包含 h+1 位,其中最高位是 1,其余各位从高到低表示从根节点到第 k 个节点的路径,0表示移动到左子节点,1 表示移动到右子节点。通过位运算得到第 k 个节点对应的路径,判断该路径对应的节点是否存在,即可判断第 k 个节点是否存在。
这个问题解决了后, 我们可以顺序搜索 二分搜索
完整代码:
func countNodes(root *TreeNode) int {
if root == nil {
return 0
}
level := 0
for node := root; node.Left != nil; node = node.Left {
level++
}
//level 表示节点满的层数
//第 n 层有 2的(n - 1)次幂 个节点,即 1 << (n - 1)
//前 n 层有 2的n次幂-1个 节点,即 (1 << n) - 1
left := 1 << level
right := 1<<(level+1) - 1
for left < right {
mid := (right-left+1)/2 + left
if nodeIsExist(root, level, mid) {
left = mid
} else {
right = mid - 1
}
}
return left
}
func nodeIsExist(root *TreeNode, level int, mid int) bool {
node := root
bits := 1 << (level - 1)
for node != nil && bits > 0 {
if bits&mid == 0 {
node = node.Left
} else {
node = node.Right
}
bits >>= 1
}
return node != nil
}
golang 借助sort包下的Search可以简化去二分查找的步骤
Search uses binary search to find and return the smallest index i in [0, n) at which f(i) is true