每日一道面试题-完全二叉树节点个数

Posted 后台技术栈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每日一道面试题-完全二叉树节点个数相关的知识,希望对你有一定的参考价值。

完全二叉树节点个数

最简单的解法就是遍历这棵树,时间复杂度是O(N),如果只是这一种解法,就不会有本文了。本文中给出两种解法。


完全二叉树

第一次看到完全二叉树的定义比较懵,搜索到的定义如下:

设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层所有的结点都连续集中在最左边,这就是完全二叉树。

谁到不想看这个定义,比较简单的理解就是和满二叉树相比较,看按层次遍历的标号是否一致。具体方案不再阐述,网上都有。


实现

  • 遍历

  • 借助完全二叉树的特点

 
   
   
 
  1. /**

  2. * Definition for a binary tree node.

  3. * type TreeNode struct {

  4. *     Val int

  5. *     Left *TreeNode

  6. *     Right *TreeNode

  7. * }

  8. */


遍历

看一下递归的公式:

  • 空树:返回0

  • 非空树:递归的统计左右子树的节点个数,返回左右子树节点个数加1的和

 
   
   
 
  1. func countNodes(root *TreeNode) int {

  2.    if root == nil {

  3.        return 0

  4.    }


  5.    sumL := countNodes(root.Left)

  6.    sumR := countNodes(root.Right)


  7.    return sumL+sumR+1

  8. }


借助完全二叉树的特点

这个特点是什么呢?完全二叉树=满二叉树+完全二叉树。完全二叉树里藏着一颗满二叉树和另外一颗完全二叉树,最惊喜的是从公式里看出子问题和原问题基本一致,可以使用递归啊。


完全二叉树的层数

这种算法的实现需要知道完全二叉树的层数,难道又需要遍历统计吗,当然不需要了,还是借助完全二叉树的特点,可以根据完全二叉树的最左节点和一个计数变量搞定,因为这个最左节点肯定是位于最后一层。

 
   
   
 
  1. func height(root *TreeNode) int {

  2.    h := 0


  3.    for root != nil {

  4.        h++

  5.        root = root.Left

  6.    }


  7.    return h

  8. }


原理

  • h=height(root), hright=height(root.Right)

  • 左子树和右子树其中有一颗是完全二叉树,另一颗是满二叉树

  • 区别左右子树的种类根据h-hright

    • 左子树:完全二叉树

    • 右子树:满二叉树

    • 左子树:满二叉树

    • 右子树:完全二叉树

    • h-hright=1:

    • h-hright=2:

  • 节点个数=1+左子树节点个数+右子树节点个数 = (1 << hright)+递归另一颗完全二叉树(满二叉树 = 1 << hright)

第一种情况

第二种情况

实现

 
   
   
 
  1. func countNodes(root *TreeNode) int {

  2.    if root == nil {

  3.        return 0

  4.    }


  5.    return nodeNums(root)

  6. }


  7. func nodeNums(root *TreeNode) int {

  8.    h := height(root)

  9.    hR := height(root.Right)


  10.    //两种情况满二叉树层数都是hR

  11.    //不同在于递归左子树还是右子树

  12.    nums := 1 << uint(hR)

  13.    if hR+1 == h {

  14.        return nums+countNodes(root.Right)

  15.    }


  16.    return nums+countNodes(root.Left)

  17. }


  18. func height(root *TreeNode) int {

  19.    h := 0


  20.    for root != nil {

  21.        h++

  22.        root = root.Left

  23.    }


  24.    return h

  25. }


时间复杂度

对于每一个节点最多需要访问深度个数的节点,所以最终时间复杂度是O(lg2*lg2)。


以上是关于每日一道面试题-完全二叉树节点个数的主要内容,如果未能解决你的问题,请参考以下文章

[每日一题] 完全二叉树节点个数

每日一道面试题-平衡二叉树的判断

一道关于二叉树的字节面试题的思考

Java实习生每日10道面试题打卡!

Java实习生每日10道面试题打卡!

每日一道编程题(85):平衡二叉树