快速求完全二叉樹的節點個數

Grey Zeng 發表於 2022-06-09
演算法

作者:Grey

原文地址:快速求完全二叉樹的節點個數

題目連結

LeetCode 222. 完全二叉樹的節點個數

題目進階要求

進階:遍歷樹來統計節點是一種時間複雜度為 O(n) 的簡單解決方案。你可以設計一個更快的演算法嗎?

暴力解法

不考慮完全二叉樹的這個性質,直接遍歷一下二叉樹,收集一下左右子樹的節點個數,然後加上頭節點,就是整個完全二叉樹的節點個數,完整程式碼如下

    public static int countNodes1(TreeNode head) {
        if (head == null) {
            return 0;
        }
        return p(head).all;
    }
    public static Info p(TreeNode head) {
        if (head == null) {
            return new Info(0);
        }
        Info leftInfo = p(head.left);
        Info rightInfo = p(head.right);
        // 收集左右子樹節點個數加上頭節點,就是整棵樹的節點個數
        int all = leftInfo.all + rightInfo.all + 1;
        return new Info(all);
    }

    public static class Info {
        public int all;
        public Info(int a) {
            all = a;
        }
    }

時間複雜度是O(N)

最優解

需要利用一下完全二叉樹的性質,首先,我們知道,樹的高度,深度,層次有如下關係:

image

對於一棵完全二叉樹,頭節點一直往左滑直到葉子節點得到的層數一定是這個二叉樹的最大層數,假設這個值為h

如果這個二叉樹右樹的最左節點的層數正好等於h,說明這個二叉樹左樹一定是滿二叉樹

image

如果這個二叉樹右樹的最左節點的層數不等於h,則說明這個二叉樹的右樹一定是滿二叉樹

image

由於滿二叉樹的節點個數可以通過樹的高度計算出來:

    public static int countNodes(TreeNode head) {
        if (head == null) {
            return 0;
        }
        int h = maxLenOfLeft(head, 1);
        return count(head, 1, h);
    }

    private static int count(TreeNode head, int level, int h) {
        if (level == h) {
            return 1;
        }
        if (maxLenOfLeft(head.right, level + 1) == h) {
            // 左樹一定是滿的
            return (1 << (h - level)) + count(head.right, level + 1, h);
        } else {
            // 右數一定是滿的,注意高度是 h - level - 1
            return (1 << (h - level - 1)) + count(head.left, level + 1, h);
        }
    }

    public static int maxLenOfLeft(TreeNode root, int level) {
        while (root != null) {
            root = root.left;
            level++;
        }
        return level - 1;
    }

通過如上方法,我們無須遍歷整個二叉樹,就可以把節點計算出來,複雜度低於O(N)

更多

演算法和資料結構筆記