LeetCode 222. Count Complete Tree Nodes

Given the root of a complete binary tree, return the number of the nodes in the tree.

According to Wikipedia, every level, except possibly the last, is completely filled in a complete binary tree, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.

Design an algorithm that runs in less than O(n) time complexity.

Example 1:

LeetCode 222. Count Complete Tree Nodes_第1张图片

Input: root = [1,2,3,4,5,6]
Output: 6

Example 2:

Input: root = []
Output: 0

Example 3:

Input: root = [1]
Output: 1

Constraints:

  • The number of nodes in the tree is in the range [0, 5 * 104].
  • 0 <= Node.val <= 5 * 104
  • The tree is guaranteed to be complete.

太难了,这题太难了!也可能是因为好久好久没做tree了。

首先先了解一下这题的complete binary tree的概念,就是所有的node都是从左到右排序。然后我们再来复习一下full binary tree的概念,就是每个node的左右都有node或者都没有node。

这题让我们求一个complete binary tree里有多少个nodes。最无脑的方法就是全部遍历一遍计算有多少个。但是这里可以用到complete binary tree的性质来优化时间复杂度,参考了:https://leetcode.com/problems/count-complete-tree-nodes/solutions/61958/concise-java-solutions-o-log-n-2/

首先我们需要一个helper function求height,这里的height定义为,如果是空就是-1,一个root的树height为0。

这篇solution里讲的我觉得有点难理解,它是通过不停往左来得到height。整个逻辑在于,先求出当前root的height比如是h,再看看root.right的height,只有两种情况:

1. h - 1:说明root.left和root.right高度一样,那么root.left必然是full binary tree with all nodes at leaf level(此时root.left的高度是h - 1),那么此时root的countNode()就是左边的node个数(2^h - 1)+右边的node个数(countNode(root.right))+root(1)

2. h - 2:此时root.left的height必然还是h -1,说明右边比左边矮,那就说明最后一个node结束在左边,于是root.right必然是full binary tree with all nodes at leaf level(此时root.right的高度是h - 2),那么此时root的countNode()就是右边的node个数(2^(h-1) - 1)+右边的node个数(countNode(root.left))+root(1)

嗯……然后用left shift代替了Math.pow(2, h)。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int countNodes(TreeNode root) {
        int h = height(root);
        if (h < 0) {
            return 0;
        }
        // left subtree has same height as right subtree, then left subtree should be full with height h - 1
        if (height(root.right) == h - 1) {
            return (1 << h) + countNodes(root.right);
        } else {
            // left subtree is higher than right subtree, then right subtree should be full with height h - 2
            return (1 << h - 1) + countNodes(root.left);
        }
    }

    private int height(TreeNode root) {
        return root == null ? -1 : 1 + height(root.left);
    }
}

然后又看了底下评论区的一个youtube视频,感觉讲的更清晰:https://youtu.be/4wPlA_InnGY

思想主要是计算一直往左的height和一直往右的height,比较left_h和right_h是否相等,如果相等的话说明是full binary tree with all nodes at leaf level(整棵树高度为left_h),如果不相等的话就对left和right分别进行countNode()再+1作为返回值。感觉这个方法要简单直观一些。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int countNodes(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int left = leftHeight(root);
        int right = rightHeight(root);
        if (left == right) {
            return (1 << left + 1) - 1;
        }
        return countNodes(root.left) + countNodes(root.right) + 1;
    }

    private int leftHeight(TreeNode root) {
        return root == null ? -1 : 1 + leftHeight(root.left);
    }

    private int rightHeight(TreeNode root) {
        return root == null ? -1 : 1 + rightHeight(root.right);
    }
}

这个solutions还提供了iterative解法,累了,下次一定。

你可能感兴趣的:(LeetCode,leetcode)