222.Count Complete Tree Nodes(Medium)

Given a complete binary tree, count the number of nodes.
給定一個完全二叉樹,計(jì)算其節(jié)點(diǎn)數(shù)

Definition of a complete binary tree from Wikipedia:In a complete binary tree every level, except possibly the last, is completely filled, 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.

  難度在于其如何優(yōu)化遞歸,縮短遞歸的次數(shù)

My Solution

(Java) Version 1 Time: Time Limit Exceeded:

  遍歷一個樹,最先想到的方法果然是遞歸,隨手就可以寫出一個最簡單的遞歸遍歷,當(dāng)然,不出意外的話,這是一定會超時的,果然就超時了,只是寫法很容易理解,留在這里作為紀(jì)念,其次是想說,無腦沒有優(yōu)化的遞歸確實(shí)是相當(dāng)慢

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public int countNodes(TreeNode root) {
        if(root == null){
            return 0;
        }
        else{
            return 1+countNodes(root.left)+countNodes(root.right);
        }
    }
}

(Java) Version 2 Time: 111ms:

  這里真的是日了dog了,我只能說向位運(yùn)算低頭,原來用Math.pow()來計(jì)算滿二叉樹的幾點(diǎn),然后就超時了,換成<<之后就赤果果地過了,我的天……
  好了,說一下思路,直接遍歷每一個節(jié)點(diǎn)是不現(xiàn)實(shí)的,所以必須通過完全二叉樹的特點(diǎn)來計(jì)算,我們可以想到,除了最下的那一層,其余的部分,都是滿二叉樹,這樣我們首先可以判斷當(dāng)前的二叉樹是不是滿二叉樹,判斷的方法是判斷樹最左和最右兩邊的長度是否相等,如果相等就可以直接計(jì)算,如果不等就進(jìn)入遞歸,分別計(jì)算左右兩顆子樹,知道只有一個節(jié)點(diǎn)的時候就停止。
  因?yàn)橥耆鏄溥M(jìn)行左右分割之后,很容易就會出現(xiàn)滿二叉樹,所以節(jié)省了大量的遍歷節(jié)點(diǎn)的時間

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public int countNodes(TreeNode root) {
        int count_left = count_length_l(root);
        int count_right = count_length_r(root);
        if(root == null){
            return 0;
        }
        else{
            if(count_left == count_right){
                return (1 << count_left)-1;
            }
            else{
                return countNodes(root.left)+countNodes(root.right)+1;
            }
        }
    }

    public int count_length_l(TreeNode root){
        int count = 0;
        while(root!=null){
            count++;
            root = root.left;
        }
        return count;
    }

    public int count_length_r(TreeNode root){
        int count = 0;
        while(root!=null){
            count++;
            root = root.right;
        }
        return count;
    }
}

(Java) Version 3 Time: 79ms:

  事實(shí)上上面那個方法就已經(jīng)過了的,不過當(dāng)時沒有想到位運(yùn)算,所以以為是遍歷的時間太長,于是重新寫了下面的這個方法,時間果然快很多,當(dāng)然如果沒有位運(yùn)算還是會超時。
  思路是把二叉樹分為左邊一顆子樹和右邊一顆子樹,分別計(jì)算兩棵樹的最左邊,然后比較,如果相等的話,就表明左邊的子樹是滿二叉樹(是不是很巧妙),如果不等的話,就表明右邊的子樹是滿二叉樹(想一下滿二叉樹的結(jié)構(gòu)),然后分別進(jìn)入遞歸就行了,我沒有認(rèn)真計(jì)算時間復(fù)雜度,但是從巧妙程度來看應(yīng)該是比上面的方法快的

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public int countNodes(TreeNode root) {
        if(root == null){
            return 0;
        }
        int count_left = count_length(root.left);
        int count_right = count_length(root.right);
        if(count_left == count_right){
            return (1 << count_left)+countNodes(root.right);
        }
        else{
            return (1 << count_right)+countNodes(root.left);
        }
    }
    
    public int count_length(TreeNode root){
        int count = 0;
        while(root!=null){
            count++;
            root = root.left;
        }
        return count;
    }
}

  很高興的一點(diǎn)是,我自己寫的兩種遍歷方式似乎就已經(jīng)是discuss中的兩大主流方法了,基本上他們的方法也是這兩種實(shí)現(xiàn),只是寫法有一點(diǎn)不同……所以下面貼了一個最詳細(xì)的大神的多種解法,好像挺有意思的……

(Java) Version 4 Time: 102ms (By StefanPochmann):

  簡短一直都是推崇的原因之一

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int height(TreeNode root) {
        return root == null ? -1 : 1 + height(root.left);
    }
    public int countNodes(TreeNode root) {
        int h = height(root);
        return h < 0 ? 0 :
               height(root.right) == h-1 ? (1 << h) + countNodes(root.right)
                                         : (1 << h-1) + countNodes(root.left);
    }
}

(Java) Version 5 Time: 63ms (By StefanPochmann):

  果然一旦擺脫了遞歸之后速度就扶搖直上,這個是一個迭代的實(shí)現(xiàn)方式,確實(shí)需要好好學(xué)習(xí)一下如何把遞歸轉(zhuǎn)化為迭代實(shí)現(xiàn)……

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int height(TreeNode root) {
        return root == null ? -1 : 1 + height(root.left);
    }
    public int countNodes(TreeNode root) {
        int nodes = 0, h = height(root);
        while (root != null) {
            if (height(root.right) == h - 1) {
                nodes += 1 << h;
                root = root.right;
            } else {
                nodes += 1 << h-1;
                root = root.left;
            }
            h--;
        }
        return nodes;
    }
}

(Java) Version 6 Time: 75ms (By StefanPochmann):

  中間循環(huán)的實(shí)現(xiàn)原理還沒有細(xì)看,應(yīng)該是把高度方法放進(jìn)了一個方法里面,其中的整合還有待琢磨,應(yīng)該有其中的巧妙之處

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int countNodes(TreeNode root) {
        if (root == null)
            return 0;
        TreeNode left = root, right = root;
        int height = 0;
        while (right != null) {
            left = left.left;
            right = right.right;
            height++;
        }
        if (left == null)
            return (1 << height) - 1;
        return 1 + countNodes(root.left) + countNodes(root.right);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,564評論 19 139
  • LeetCode 刷題隨手記 - 第一部分 前 256 題(非會員),僅算法題,的吐槽 https://leetc...
    蕾娜漢默閱讀 18,391評論 2 36
  • 樹的概述 樹是一種非常常用的數(shù)據(jù)結(jié)構(gòu),樹與前面介紹的線性表,棧,隊(duì)列等線性結(jié)構(gòu)不同,樹是一種非線性結(jié)構(gòu) 1.樹的定...
    Jack921閱讀 4,762評論 1 31
  • 我曾去醫(yī)院做義工。剛開始進(jìn)到醫(yī)院的時候,我聞著空氣中淡淡的消毒水的味道很不舒服,或許是醫(yī)院以往帶給我的感受都...
    喬木于南方閱讀 146評論 0 0
  • 其實(shí)很簡單 其實(shí)很自然 其實(shí)很簡單 其實(shí)并不難 ...... 很早就聽過這首歌,只是不知道叫什么名字。今天再聽到,...
    一一KK閱讀 308評論 0 0

友情鏈接更多精彩內(nèi)容