算法学习记录(一零四)

146 阅读2分钟

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

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

image.png

解:

  1. 利用完全二叉树的特性,即对于一个节点来说,如果它的右子树深度不等于整棵树的深度,那么右子树就是满二叉树。反之左子树就是满二叉树
  2. 所以,先遍历二叉树的左边界求出树的深度,然后开始递归。
  3. 递归参数含义为,node:当前节点。deep:当前节点深度
  4. 遍历当前节点右子树的左边界,求右子树能达到的深度。如果右子树深度等于整棵树的深度,那么已知当前节点深度、整棵树深度、左子树是满二叉树,就可以求出左子树的节点个数。然后去递归计算当前节点的右子树。
  5. 如果右子树深度不等,那么已知当前节点深度、右子树深度、右子树是满二叉树,就可以求出右子树节点个数。然后去递归计算当前节点的左子树。
  6. 上述两种情况,计算出子树节点个数之后,就把子树节点数 + 1(即当前节点)累加到resCount中,最终返回resCount
const countNodes = function(root) {
    if (!root) return 0
    let curNode = root
    let treeDeep = 1
    let resCount = 0
    // 计算树的深度
    while (curNode?.left) {
        treeDeep++
        curNode = curNode.left
    }
    const getRes = (node, deep) => {
        if (!node) return 
        // 计算右子树深度
        let curNode = node.right
        let rightDeep = curNode ? deep + 1 : deep
        while (curNode?.left) {
            rightDeep++
            curNode = curNode.left
        }
        // 如果右树深度等于树的深度,那么意味着左子树是满二叉树
        if (rightDeep === treeDeep) {
            // 计算左子树节点个数 + 根节点并累加
            resCount += 2 ** (treeDeep - deep)
            // 递归计算右子树的节点个数
            getRes(node.right, deep + 1)
        } else {
            // 右子树深度小于树的深度,意味着右子树是满二叉树
            // 计算右子树节点个数并累加
            resCount += 2 ** (rightDeep - deep)
            // 递归计算左子树节点个数+根节点
            getRes(node.left, deep + 1)
        }
    }
    getRes(root, 1)
    return resCount
};