Leetcode - Count Complete Tree Nodes

Paste_Image.png

My code:

/**
 * 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 left = 1 + getLeftHeight(root);
        int right = 1 + getRightHeight(root);
        if (left == right)
            return (1 << left) - 1;
        else
            return 1 + countNodes(root.left) + countNodes(root.right);
    }
    
    private int getLeftHeight(TreeNode root) {
        if (root == null)
            return 0;
        int height = 0;
        while (root.left != null) {
            height++;
            root = root.left;
        }
        return height;
    }
    
    private int getRightHeight(TreeNode root) {
        if (root == null)
            return 0;
        int height = 0;
        while (root.right != null) {
            height++;
            root = root.right;
        }
        return height;
    }
    
    public static void main(String[] args) {
        Solution test = new Solution();
        TreeNode n1 = new TreeNode(1);
        System.out.println(test.countNodes(n1));
    }
} 

My test result:


Paste_Image.png

這道題目最簡單的做法,就是直接隨便遍歷。但肯定是不對的,太慢了。
我也在想辦法,利用完整樹的特性。
但是最后沒做出來。
具體做法看下這個博客吧。寫的很清楚。
http://www.programcreek.com/2014/06/leetcode-count-complete-tree-nodes-java/

programcreek 好網站

**
總結: 之前有道題目,kth Smallest number 也是采用了把樹劈成兩半,左右各自統計結點個數。
而這道題目,同樣是左右各自遍歷。雖然具體細節不同。
但是可以看出,這也算是樹的遍歷方式的一種。
Tree 免費的medium和easy差不多都做完了,還差兩道easy。
感覺樹的遍歷方式有如下幾種。
pre-order top-down
in-order sort-order for BST
post-order bottom-up

然后遞歸形式我可以很輕松地寫出來。但是非遞歸形式不會寫。
所以這三種遍歷的非遞歸,要在這周末前學會寫!!!!

然后,level-order
left to right
right to left
zigzag (use two stacks)

然后,
這道題目的遍歷方式,分別遍歷左子樹與右子樹,統計信息。
然后繼續遍歷左子樹的左子樹與右子樹。。。。
以此循環。

同時,設置一些全局的私有變量,有時候會方便寫代碼。
**

Anyway, Good luck, Richardo!

My code:

/**
 * 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;
        return helper(root);
    }
    
    private int helper(TreeNode root) {
        if (root == null)
            return 0;
        int left = getLeftDepth(root);
        int right = getRightDepth(root);
        if (left == right)
            return (int) (2 << (left - 1)) - 1;
        else
            return 1 + helper(root.left) + helper(root.right);
    }
    
    private int getLeftDepth(TreeNode root) {
        int counter = 0;
        while (root != null) {
            counter++;
            root = root.left;
        }
        return counter;
    }
    
    private int getRightDepth(TreeNode root) {
        int counter = 0;
        while (root != null) {
            counter++;
            root = root.right;
        }
        return counter;
    }
}

這道題目第二次做還是沒做出來。
就是用二分法做。
其中, 用左移位求 2 ^ n 速度更快。 如果用 Math.pow(2, n); 會超時。
參考網頁:
http://www.programcreek.com/2014/06/leetcode-count-complete-tree-nodes-java/

另外,衍生出來一個問題,如果判斷一棵樹是不是complete
我寫了一段代碼如下:
My code:

public boolean isFullBT(TreeNode root) {
        if (root == null)
            return false;
        Queue<TreeNode> q = new LinkedList<TreeNode>();
        q.offer(root);
        boolean totalNull = false;
        while (!q.isEmpty()) {
            int size = q.size();
            for (int i = 0; i < size; i++) {
                TreeNode curr = q.poll();
                if (curr.left != null) {
                    if (totalNull)
                        return false;
                    q.offer(curr.left);
                }
                else if (curr.left == null) {
                    totalNull = true;
                }
                if (curr.right != null) {
                    if (totalNull)
                        return false;
                    q.offer(curr.right);
                }
                else if (curr.right == null) {
                    totalNull = true;
                }
            }
        }
        return true;
    }

自己寫出來的。

可以參考下下面兩個網頁:
http://www.geeksforgeeks.org/check-if-a-given-binary-tree-is-complete-tree-or-not/

http://www.geeksforgeeks.org/check-whether-binary-tree-complete-not-set-2-recursive-solution/

Anyway, Good luck, Richardo!

My code:

/**
 * 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 h = height(root);
        if (h == -1) {
            return 0;
        }
        else {
            int right = height(root.right);
            if (right == h - 1) {
                return (1 << h) + countNodes(root.right);
            }
            else {
                return (1 << (h - 1)) + countNodes(root.left);
            }
        }
    }
    
    private int height(TreeNode root) {
        if (root == null) {
            return -1;
        }
        return 1 + height(root.left);
    }
}

這道題目我的做法超時了,即使換成 比特移位操作。
然后看了答案,覺得還是醍醐灌頂。

做大的變化在于右子樹。
右子樹高度和左子樹之差,可能是0,可能是1
當差是0, 那么左子樹一定會complete,那么我們可以用公式先計算出 左子樹 + 根節點個數,然后recursion計算,右子樹結點個數
當差是1,那么,右子樹一定是complete tree,只不過高度少了1,移位的時候,少向右移動移位即可。然后我們需要recursive計算出,左子樹的結點個數。
差不多就這么個思路。

iteration的做法也是如此:

My code:

/**
 * 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 h = height(root);
        int ret = 0;
        while (root != null) {
            int right = height(root.right);
            if (right == h - 1) {
                ret += (1 << h);
                root = root.right;
            }
            else {
                ret += (1 << (h - 1));
                root = root.left;
            }
            h--;
        }
        
        return ret;
    }
    
    private int height(TreeNode root) {
        if (root == null) {
            return -1;
        }
        return 1 + height(root.left);
    }
}

reference:
https://discuss.leetcode.com/topic/15533/concise-java-solutions-o-log-n-2

上一下我寫的TLE的解法:

My code:

/**
 * 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;
        }
        
        return helper(root);
    }
    
    private int helper(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int left = getMaxDepth(root.left);
        int right = getMinDepth(root.right);
        if (left == right) {
            return (1 << (left + 1)) - 1;
        }
        else {
            int leftMin = getMinDepth(root.left);
            if (left == leftMin) {
                return (1 << left) + helper(root.right);
            }
            else {
                return helper(root.left) + 1 + helper(root.right);      
            }
        }
    }
    
    private int getMaxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        return Math.max(getMaxDepth(root.left), getMaxDepth(root.right)) + 1;
    }
    
    private int getMinDepth(TreeNode root) {
        if (root == null) {
            return 0;
        }
        else {
            return Math.min(getMinDepth(root.left), getMinDepth(root.right)) + 1;
        }
    }
}

如何判斷一棵樹是否為complete?
就判斷 左子樹的最大深度和右子樹的最小深度是否相等。
如果相等,就是complete

Anyway, Good luck, Richardo! -- 09/07/2016

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容

  • 背景 一年多以前我在知乎上答了有關LeetCode的問題, 分享了一些自己做題目的經驗。 張土汪:刷leetcod...
    土汪閱讀 12,762評論 0 33
  • 總結類型: 完全子樹(#222) BST(左右子樹值的性質,注意不僅要滿足parent-child relatio...
    __小赤佬__閱讀 704評論 0 0
  • LeetCode 刷題隨手記 - 第一部分 前 256 題(非會員),僅算法題,的吐槽 https://leetc...
    蕾娜漢默閱讀 17,878評論 2 36
  • 目錄 簡書的 markdown 都不支持 [TOC] 語法……我就不貼目錄了。下面按照類別,列出了29道關于二叉樹...
    被稱為L的男人閱讀 3,333評論 0 8
  • 由OpenDigg 出品的前端開源項目周報第七期來啦。我們的前端開源周報集合了OpenDigg一周來新收錄的優質的...
    OpenDigg閱讀 419評論 1 2