1. 程式人生 > 其它 >leetcode(11)二叉樹的屬性系列題目

leetcode(11)二叉樹的屬性系列題目

104. 二叉樹的最大深度

遞迴法
可以使用前序遍歷(中左右),也可以使用後序遍歷(左右中),使用前序求的就是深度,使用後序求的是高度。
而根節點的高度就是二叉樹的最大深度

class Solution:
    def maxDepth(self, root: Optional[TreeNode]) -> int:
        return self.getHeight(root)
    
    def getHeight(self, root):
        if not root:
            return 0
        leftHeight = self.getHeight(root.left)
        rightHeight = self.getHeight(root.right)
        return max(leftHeight, rightHeight) + 1

111. 二叉樹的最小深度

遞迴法

class Solution:
    def minDepth(self, root: TreeNode) -> int:
        if not root:
            return 0
        if not root.left and not root.right:
            return 1
        res = float('inf')
        if root.left:
            res = min(res, self.minDepth(root.left))
        if root.right:
            res = min(res, self.minDepth(root.right))
        return res + 1

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

迭代法,按照普通二叉樹的方法

class Solution:
    def countNodes(self, root: TreeNode) -> int:
        if not root:
            return 0
        res = 0
        
        from collections import deque
        que = deque([root])

        while que:
            size = len(que)
            for _ in range(size):
                cur = que.popleft()
                if cur.left:
                    que.append(cur.left)
                if cur.right:
                    que.append(cur.right)
                res += 1
        return res

遞迴法,利用完全二叉樹的性質,求深度
只有兩種情況:

  • 情況一:就是滿二叉樹,可以直接用 2^樹深度 - 1 來計算,注意這裡根節點深度為1。

  • 情況二:最後一層葉子節點沒有滿,分別遞迴左孩子,和右孩子,遞迴到某一深度一定會有左孩子或者右孩子為滿二叉樹,然後依然可以按照情況1來計算。

class Solution:
    def countNodes(self, root: TreeNode) -> int:
        if not root:
            return 0
        
        left = root.left
        right = root.right
        #這裡初始為0是有目的的,為了下面求指數方便
        leftHeight = 0
        rightHeight = 0
        #求左子樹深度
        while left:
            left = left.left
            leftHeight += 1
        #求右子樹深度
        while right:
            right = right.right
            rightHeight += 1

        if leftHeight == rightHeight:
            return (2 << leftHeight) - 1  #注意(2<<1) 相當於2^2,所以leftHeight初始為0
        
        return self.countNodes(root.left) + self.countNodes(root.right) + 1

110. 平衡二叉樹

  • 二叉樹節點的深度:指從根節點到該節點的最長簡單路徑邊的條數。
  • 二叉樹節點的高度:指從該節點到葉子節點的最長簡單路徑邊的條數。
    求深度適合用前序遍歷,而求高度適合用後序遍歷。

    遞迴法,後序遍歷
class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        if self.getHeight(root) != -1:
            return True
        else:
            return False
        
    def getHeight(self, root):
        if not root:
            return 0
        leftHeight = self.getHeight(root.left)
        rightHeight = self.getHeight(root.right)
        if leftHeight == -1 or rightHeight == -1 or abs(leftHeight - rightHeight) >1:
            return -1
        else:
            return max(leftHeight, rightHeight) + 1

257. 二叉樹的所有路徑

需要前序遍歷,這樣才方便讓父節點指向孩子節點,找到對應的路徑。

在這道題目中將第一次涉及到回溯,因為我們要把路徑記錄下來,需要回溯來回退一一個路徑在進入另一個路徑。
遞迴法+隱形回溯

class Solution:
    def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
        if not root:
            return []
        path = ''
        res = []
        self.traversal(root, path, res)
        return res
    
    def traversal(self, root, path, res):
        path += str(root.val)
        # 若當前節點為leave,直接輸出
        if not root.left and not root.right:
            res.append(path)
        if root.left:
            self.traversal(root.left, path + '->', res)  # + '->' 是隱藏回溯
        if root.right:
            self.traversal(root.right, path + '->', res)

543. 二叉樹的直徑

注意:一條路徑的長度為該路徑經過的節點數減一,所以求直徑(即求路徑長度的最大值)等價於求路徑經過節點數的最大值減一
而任意一條路徑均可以被看作由某個節點為起點,從其左兒子和右兒子向下遍歷的路徑拼接得到

class Solution:
    def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:
        self.res = 0  # 0或1都可以
        def depth(root):
            # 訪問到空節點了,返回0
            if not root:
                return 0
            # 左兒子為根的子樹的深度
            leftDep = depth(root.left)
            # 右兒子為根的子樹的深度
            rightDep = depth(root.right)
            # 計算d_node即L+R+1 並更新res
            self.res = max(self.res, leftDep + rightDep + 1)
            # 返回該節點為根的子樹的深度
            return max(leftDep, rightDep) + 1
        depth(root)
        return self.res - 1

124. 二叉樹中的最大路徑和

注意:與543. 二叉樹的直徑 的區別是注意節點值為負的情況

class Solution:
    def __init__(self):
        self.maxSum = float('-inf')

    def maxPathSum(self, root: Optional[TreeNode]) -> int:
        def maxGain(root):
            if not root:
                return 0
            # 遞迴計算左右子節點的最大貢獻值
            # 只有在最大貢獻值大於 0 時,才會選取對應子節點
            leftGain = max(maxGain(root.left), 0)
            rightGain = max(maxGain(root.right), 0)
            # 節點的最大路徑和取決於該節點的值與該節點的左右子節點的最大貢獻值
            curGain = root.val + leftGain + rightGain
            # 更新答案
            self.maxSum = max(self.maxSum, curGain)
             # 返回節點的最大貢獻值
            return root.val + max(leftGain, rightGain)

        maxGain(root)
        return self.maxSum