(LeetCode)二叉樹

0. 總結

二叉樹的核心就是用遞歸的思想解決問題,三個要素分析清楚:

  1. 尋求遞歸的子問題,子問題就是要解決的問題落實到一個(帶左右孩子的)節點上時應該怎麼做;
  2. 遞歸終止條件
  3. 遞歸返回值

1. 合併二叉樹

617. merge-two-binary-trees
在這裏插入圖片描述

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

class Solution(object):

    def mergeTrees(self, t1, t2):
        """
        :type t1: TreeNode
        :type t2: TreeNode
        :rtype: TreeNode

        """
        if t1 is None:
            return t2
        if t2 is None:
            return t1
        
        t1.val += t2.val
        t1.left = self.mergeTrees(t1.left, t2.left)
        t1.right = self.mergeTrees(t1.right, t2.right)

        return t1

2. 翻轉二叉樹

226. invert-binary-tree
在這裏插入圖片描述

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

class Solution(object):
    def invertTree(self, root):
        """
        :type root: TreeNode
        :rtype: TreeNode
        """
        if root is None:
            return None

        root.left, root.right = root.right, root.left
        self.invertTree(root.left)
        self.invertTree(root.right)

        return root

3. 二叉樹的最大深度

104. maximum-depth-of-binary-tree
在這裏插入圖片描述

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

class Solution(object):
    def maxDepth(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        if root is None:
            return 0

        return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))

4. 把二叉搜索樹轉換爲累加樹

538. convert-bst-to-greater-tree

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

class Solution(object):
    def __init__(self):
        self.acc = 0

    def convertBST(self, root):
        """
        :type root: TreeNode
        :rtype: TreeNode

        二叉樹遍歷:右 根 左
        """
        if root is None:
            return None
        
        self.convertBST(root.right)
        root.val += self.acc
        self.acc = root.val
        self.convertBST(root.left)

        return root

5. 對稱二叉樹

101. symmetric-tree
在這裏插入圖片描述

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

class Solution(object):
    def isSymmetric(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        
        笨辦法
            分別 根左右、根右左 遍歷這棵樹,比較生成的元素是否一一相等
            (注意遍歷的時候None也要考慮進去)
        
        聰明辦法
            兩個指針指向同一棵樹,同步移動,一個向左、一個向右,檢查是否相等

        """

        def check_node(t1, t2):
            if not t1 and not t2:
                return True
            if not t1 or not t2:
                return False
            return t1.val == t2.val and check_node(t1.left, t2.right) and check_node(t1.right, t2.left)
        
        return check_node(root, root)

6. 二叉樹的直徑

543. diameter-of-binary-tree
在這裏插入圖片描述

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

class Solution(object):

    def __init__(self):
        self.max_path_len = 0

    def diameterOfBinaryTree(self, root):
        """
        :type root: TreeNode
        :rtype: int

        解法
            任意兩節點的路徑都可以表示爲 以某個節點爲根的左右子樹深度之和
            最長直徑,就是由 左右子樹深度之和最大的子樹(以任意節點爲根) 產生的
        """
        # 笨辦法遞歸
        # def max_depth(root):
        #     if not root:
        #         return 0
        #     return 1 + max(max_depth(root.left), max_depth(root.right))
        
        # if not root:
        #     return 0
        # path_len = max_depth(root.left) + max_depth(root.right)
        # self.max_path_len = max(self.max_path_len, path_len)
        # self.diameterOfBinaryTree(root.left)
        # self.diameterOfBinaryTree(root.right)

        # return self.max_path_len

        # 在求數最大深度遞歸算法的基礎上增加求極值
        def max_depth(root):
            if not root:
                return 0
            l_depth = max_depth(root.left)
            r_depth = max_depth(root.right)
            self.max_path_len = max(self.max_path_len, l_depth+r_depth)
            return 1 + max(l_depth, r_depth)

        max_depth(root)
        return self.max_path_len

7. 二叉樹的中序遍歷

94. binary-tree-inorder-traversal

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

class Solution(object):
    def inorderTraversal(self, root):
        """
        :type root: TreeNode
        :rtype: List[int]

        思路
            遞歸算法簡單

            非遞歸用循環和棧實現
        """

        result = []
        stack = []
        node = root
        while node or stack:
            while node:
                stack.append(node)  # 左鏈入棧
                node = node.left
            node = stack.pop()
            result.append(node.val)  # 輸出
            node = node.right  # 右鏈
        return result

8. 二叉樹展開爲鏈表

114. flatten-binary-tree-to-linked-list

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def flatten(self, root):
        """
        :type root: TreeNode
        :rtype: None Do not return anything, modify root in-place instead.

        思路
            先序遍歷二叉樹, 將結果保存到一個數組
            迭代數組, 重鏈指針

            或者使用後序遍歷, 直接在traverse內部重鏈, 需使用一個全局變量pre
        """
        def traverse(root, array):
            if not root:
                return
            array.append(root)
            traverse(root.left, array)
            traverse(root.right, array)

        array = []
        traverse(root, array)

        for i in range(len(array)-1):
            array[i].left = None
            array[i].right = array[i+1]
        

9. 從前序與中序遍歷序列構造二叉樹

105. construct-binary-tree-from-preorder-and-inorder-traversal
在這裏插入圖片描述

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

class Solution(object):
    def buildTree(self, preorder, inorder):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode

        思路
            前序遍歷:[ 根節點, [左子樹的前序遍歷結果], [右子樹的前序遍歷結果] ]
            中序遍歷:[ [左子樹的中序遍歷結果], 根節點, [右子樹的中序遍歷結果] ]
            根據前序遍歷拿到根節點, 用根節點到中序遍歷結果find, 找到左子樹結果與右子樹結果分界點
            遞歸對左右子樹, 以同樣的方式構建
        """

        if not preorder or not inorder:
            return None
        
        node = TreeNode(preorder[0])
        node_idx = inorder.index(preorder[0])
        node.left = self.buildTree(preorder[1:node_idx+1], inorder[:node_idx])
        node.right = self.buildTree(preorder[node_idx+1:], inorder[node_idx+1:])

        return node

10. 不同的二叉搜索樹

96. unique-binary-search-trees
在這裏插入圖片描述

class Solution(object):
    def numTrees(self, n):
        """
        :type n: int
        :rtype: int

        思路
            題目滿足卡塔蘭數, 請參考下面資料
            https://baike.baidu.com/item/catalan/7605685?fr=aladdin
            https://leetcode-cn.com/problems/unique-binary-search-trees/solution/bu-tong-de-er-cha-sou-suo-shu-by-leetcode/
        """
        C = 1
        for i in range(0, n):
            C = C * 2*(2*i+1)/(i+2)
        return int(C)

11. 二叉樹的最近公共祖先

236. lowest-common-ancestor-of-a-binary-tree
在這裏插入圖片描述
在這裏插入圖片描述

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

class Solution(object):
    def lowestCommonAncestor(self, root, p, q):
        """
        :type root: TreeNode
        :type p: TreeNode
        :type q: TreeNode
        :rtype: TreeNode

        思路
            將每個節點的父節點存到一個字典裏面,
            分別從p, q兩個節點往上走, 最先相遇的即是最近公共祖先
        """

        def save_parents(root):
            if not root:
                return
            if root.left:
                parents[root.left] = root
            if root.right:
                parents[root.right] = root
            save_parents(root.left)
            save_parents(root.right)
        
        def get_node_parents(node):  # 獲取node的所有父親, 從近到遠, 包含自身
            node_parents = [node]
            while node in parents:
                node_parents.append(parents[node])
                node = parents[node]
            return node_parents
        
        parents = {}
        save_parents(root)

        p_parents, q_parents = get_node_parents(p), get_node_parents(q)
        for i in range(min(len(p_parents), len(q_parents))):  # p和q屬於不同子樹
            if p_parents[-i-1] == q_parents[-i-1]:
                continue
            return p_parents[-i]
        # p和q在同棵子樹
        nearest_parent = p_parents[0] if len(p_parents) < len(q_parents) else q_parents[0]

        return nearest_parent

12. 二叉樹的層序遍歷

102. binary-tree-level-order-traversal
在這裏插入圖片描述

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

class Solution(object):
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]

        思路
            帶棧深度地遍歷二叉樹, 將節點按棧深保存到result
        """
        def traverse(root, depth, result):
            if not root:
                return
            if depth >= len(result):
                result.append([])
            result[depth].append(root.val)
            traverse(root.left, depth+1, result)
            traverse(root.right, depth+1, result)
        
        result = []
        traverse(root, 0, result)
        
        return result

13. 路徑總和 III

437. path-sum-iii
在這裏插入圖片描述

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

class Solution(object):

    def __init__(self):
        self.path_num = 0

    def pathSum(self, root, sum):
        """
        :type root: TreeNode
        :type sum: int
        :rtype: int

        思路
        	兩重遞歸
            1. 從根節點開始遍歷,計算滿足條件的路徑條數;(假設路徑一定從根節點開始)
            2. 分別以所有節點爲根節點,計算路徑總條數;
        """
        if root is None:
            return 0

        self.path(root, sum)
        self.pathSum(root.left, sum)
        self.pathSum(root.right, sum)

        return self.path_num
        
    def path(self, root, sum):
        if root is None:
            return
        
        sum -= root.val
        if sum == 0:
            self.path_num += 1
        
        self.path(root.left, sum)
        self.path(root.right, sum)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章