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阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,719评论 0 33
  • 总结类型: 完全子树(#222) BST(左右子树值的性质,注意不仅要满足parent-child relatio...
    __小赤佬__阅读 676评论 0 0
  • LeetCode 刷题随手记 - 第一部分 前 256 题(非会员),仅算法题,的吐槽 https://leetc...
    蕾娜漢默阅读 17,676评论 2 36
  • 目录 简书的 markdown 都不支持 [TOC] 语法……我就不贴目录了。下面按照类别,列出了29道关于二叉树...
    被称为L的男人阅读 3,280评论 0 8
  • 由OpenDigg 出品的前端开源项目周报第七期来啦。我们的前端开源周报集合了OpenDigg一周来新收录的优质的...
    OpenDigg阅读 399评论 1 2