222. Count Complete Tree Nodes

222. Count Complete Tree Nodes

線性搜索

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def countNodes(self, root: Optional[TreeNode]) -> int:

        def dfs(node):
            if not node:
                return 0
            if not node.left and not node.right:
                return 1
            left = dfs(node.left)
            right = dfs(node.right)
            return left+right+1

        return dfs(root)

這樣的時間複雜度是 $$O(n)$$ ,老實說其實不差,不過這個題目存在這另一個更快速的解法,這個不容易想到,不過不算很難理解。

二分搜索

上面的作法並沒有使用到題目給的 Complete Tree 的特性,那就是樹的每一層都是完整的結構,除了最後一層。

這個方法要想到確實不簡單,在面試時要寫出 bug free 也滿困難的。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:

    def getDepth(self, node: Optional[TreeNode]) -> int:
        depth = 0
        while node.left:
            node = node.left
            depth += 1
        return depth

    def exists(self, idx, depth, node) -> bool:
        left = 0
        right = 2 ** depth - 1
        for _ in range(depth):
            mid = left + (right - left)//2
            if idx <= mid:
                node = node.left
                right = mid
            else:
                node = node.right
                left = mid + 1
        return node is not None

    def countNodes(self, root: Optional[TreeNode]) -> int:

        if not root:
            return 0

        depth = self.getDepth(root)

        if depth == 0:
            return 1

        left = 1
        right = 2 ** depth - 1
        while left <= right:
            mid = left + (right - left)//2
            if self.exists(mid, depth, root):
                left = mid + 1
            else:
                right = mid - 1

        return 2**depth - 1 + left