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:

Input: root = [1,2,3,4,5,6] Output: 6
Example 2:
Input: root = [] Output: 0
Example 3:
Input: root = [1] Output: 1
Constraints:
[0, 5 * 104].0 <= Node.val <= 5 * 104太难了,这题太难了!也可能是因为好久好久没做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解法,累了,下次一定。