• 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:

    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)。

    1. /**
    2. * Definition for a binary tree node.
    3. * public class TreeNode {
    4. * int val;
    5. * TreeNode left;
    6. * TreeNode right;
    7. * TreeNode() {}
    8. * TreeNode(int val) { this.val = val; }
    9. * TreeNode(int val, TreeNode left, TreeNode right) {
    10. * this.val = val;
    11. * this.left = left;
    12. * this.right = right;
    13. * }
    14. * }
    15. */
    16. class Solution {
    17. public int countNodes(TreeNode root) {
    18. int h = height(root);
    19. if (h < 0) {
    20. return 0;
    21. }
    22. // left subtree has same height as right subtree, then left subtree should be full with height h - 1
    23. if (height(root.right) == h - 1) {
    24. return (1 << h) + countNodes(root.right);
    25. } else {
    26. // left subtree is higher than right subtree, then right subtree should be full with height h - 2
    27. return (1 << h - 1) + countNodes(root.left);
    28. }
    29. }
    30. private int height(TreeNode root) {
    31. return root == null ? -1 : 1 + height(root.left);
    32. }
    33. }

    然后又看了底下评论区的一个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作为返回值。感觉这个方法要简单直观一些。

    1. /**
    2. * Definition for a binary tree node.
    3. * public class TreeNode {
    4. * int val;
    5. * TreeNode left;
    6. * TreeNode right;
    7. * TreeNode() {}
    8. * TreeNode(int val) { this.val = val; }
    9. * TreeNode(int val, TreeNode left, TreeNode right) {
    10. * this.val = val;
    11. * this.left = left;
    12. * this.right = right;
    13. * }
    14. * }
    15. */
    16. class Solution {
    17. public int countNodes(TreeNode root) {
    18. if (root == null) {
    19. return 0;
    20. }
    21. int left = leftHeight(root);
    22. int right = rightHeight(root);
    23. if (left == right) {
    24. return (1 << left + 1) - 1;
    25. }
    26. return countNodes(root.left) + countNodes(root.right) + 1;
    27. }
    28. private int leftHeight(TreeNode root) {
    29. return root == null ? -1 : 1 + leftHeight(root.left);
    30. }
    31. private int rightHeight(TreeNode root) {
    32. return root == null ? -1 : 1 + rightHeight(root.right);
    33. }
    34. }

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

  • 相关阅读:
    Linux学习之MySQL建表
    打卡web基础学习
    演示spring AOP的切入表达式重用和优先级问题以及怎么实现基于xml的AOP
    劲(很)霸(不)酷(好)炫(用)的NLP可视化包:Dodorio 使用指北
    MongoDB学习笔记
    树莓派4B_OpenCv学习笔记10:调整视频帧大小
    鸿蒙介绍、鸿蒙编程环境、基本组件、页面跳转学习
    项目问题:使用Mybatis对Oracle查询数据记录时,navicat查询有记录,但是mybatis查询返回null
    Stable Diffusion原理
    Oracle 误删表后数据恢复操作
  • 原文地址:https://blog.csdn.net/qq_37333947/article/details/132832793