Leetcode題解 - 樹部分簡單題目代碼+思路(10五、10六、10九、1十二、89七、25七、87二、22六、23五、129)

樹的題目中遞歸用的比較多(可是遞歸是真難弄 我🍂了,此次也忘記加上題目了,下次注意🤥node


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

class Solution:
    def buildTree(self, preorder, inorder) -> TreeNode:
        if len(preorder) == 0 or len(inorder) == 0:
            return
        # 若是隻有一個確定是"根"就直接返回
        if len(preorder) == 1 and len(inorder) == 1:
            return TreeNode(preorder[0])
        root = TreeNode(preorder[0])
        ind = inorder.index(preorder[0])
        # 遞歸構造左子樹部分
        root.left = self.buildTree(preorder[1:ind+1], inorder[:ind])
        # 遞歸構造右子樹部分
        root.right = self.buildTree(preorder[ind+1:], inorder[ind+1:])
        return root

106. 從中序與後序遍歷序列構造二叉樹

"""
遞歸構造, 中序遍歷爲左根右,後序遍歷爲左右根。
每次找到根的位置再遞歸去構建左右子樹。
"""
class Solution:
    def buildTree(self, inorder, postorder) -> TreeNode:
        if len(inorder) == 0 or len(postorder) == 0:
            return
        if len(inorder) == 1 and len(postorder) == 1:
            return TreeNode(postorder[-1])
        root = TreeNode(postorder[-1])
        ind = inorder.index(postorder[-1])
        root.left = self.buildTree(inorder[:ind], postorder[:ind])
        root.right = self.buildTree(inorder[ind+1:], postorder[ind:-1])
        return root

109. 有序鏈表轉換二叉搜索樹 - 和樓上一樣的題型

# 109. 有序鏈表轉換二叉搜索樹
"""
將鏈表想象成一根繩子,每次都抓住最中間的部分做爲根,遞歸實現。(相似於中序、後序還原一顆樹)
"""
class Solution:
    def sortedListToBST(self, head: ListNode) -> TreeNode:
        lNum = []
        while head:
            lNum.append(head.val)
            head = head.next
        def DFS(l):
            if len(l) == 0:
                return
            if len(l) == 1:
                return TreeNode(l[0])
            rootInd = len(l) // 2
            root = TreeNode(l[rootInd])
            root.left = DFS(l[:rootInd])
            root.right = DFS(l[rootInd+1:])
            return root
        return DFS(lNum)

112. 路徑總和

class Solution:
    def hasPathSum(self, root, sum: int) -> bool:
        def DFS(root, s):
            if not root:
                return False
            if not root.left and not root.right and s - root.val == 0:
                return True
            return DFS(root.left, s-root.val) or DFS(root.right, s-root.val)
        return DFS(root, sum)

897. 遞增順序查找樹

class Solution:
    def increasingBST(self, root: TreeNode) -> TreeNode:
        if not root:
            return 
        Inor = []
        # 先中序遍歷獲取序列
        def Inorder(root):
            if not root:
                return
            Inorder(root.left)
            Inor.append(root.val)
            Inorder(root.right)
        Inorder(root)
        rootNode = TreeNode(Inor.pop(0))
        # tree存放已經建好的結點
        tree = [rootNode]
        # 建樹
        while len(Inor) != 0:
            node = tree.pop(0)
            tmp = Inor.pop(0)
            newnode = TreeNode(tmp)
            node.right = newnode
            tree.append(newnode)
        return rootNode

257. 二叉樹的全部路徑

"""
想不出來遞歸就想特殊狀況:
` 空樹如何處理
` 只有一個根節點的如何處理
` 有一個根節點一個左節點一個右節點的如何處理
"""
class Solution:
    def binaryTreePaths(self, root):
        res = []

        def DFS(root, tmp):
           if not root:
               return
           if not root.left and not root.right:
                res.append((tmp+[str(root.val)]).copy())
                return
           # 不改變原始tmp的狀態
           if root.left:
               DFS(root.left, tmp+[str(root.val)])
           if root.right:
               DFS(root.right, tmp+[str(root.val)])
        DFS(root, [])
        return ["->".join(tmp) for tmp in res]

872. 葉子類似的樹

"""
一開始考慮的是利用BFS獲取全部的葉子節點,但這是不行的,由於BFS是一層一層來的全部最後葉子結點序列的順序會和期待的結果不一樣。
再考慮使用DFS,由於題目規定的是從左到右的葉子結點的順序因此應該是DFS。
"""
class Solution:
    def leafSimilar(self, root1: TreeNode, root2: TreeNode) -> bool:
        def DFS(root, tmp):
            if not root:
                return []
            if not root.left and not root.right:
                tmp.append(root.val)
            if root.left:
                DFS(root.left, tmp)
            if root.right:
                DFS(root.right, tmp)
            return tmp
        res1 = DFS(root1, [])
        # print(res1)
        res2 = DFS(root2, [])
        # print(res2)
        if res1 == res2:
            return True
        return False

226. 翻轉二叉樹

"""
根不變,左子樹變成右子樹,右子樹變成左子樹。
"""
class Solution:
    def invertTree(self, root: TreeNode) -> TreeNode:
        if not root:
            return
        newroot = TreeNode(root.val)
        newroot.left = self.invertTree(root.right)
        newroot.right = self.invertTree(root.left)
        return newroot

235. 二叉搜索樹的最近公共祖先 - 能夠引伸到任何結點的最近公共祖先

"""
並無用到題中給出的二叉搜索樹的良好性質。

先記錄每個節點的父節點,再從目標節點一直走到根節點,判斷兩個目標節點走到根節點路徑中重合的第一個點
"""
class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if not root:
            return
        Q = [root]
        # parent[i]表示值爲i的結點的父節點
        parent = dict()
        parent[root.val] = TreeNode(-1)
        while len(Q) != 0:
            node = Q.pop(0)
            if node.left:
                parent[node.left.val] = node
                Q.append(node.left)
            if node.right:
                parent[node.right.val] = node
                Q.append(node.right)

        # 找到從目標節點到根節點的路徑
        def findPath(tarNode, res):
            res.append(tarNode.val)
            while parent[tarNode.val].val != -1:
                res.append(parent[tarNode.val].val)
                tarNode = parent[tarNode.val]
            return res
        # 找到兩條路徑的交叉點
        p1 = findPath(p, [])
        p2 = findPath(q, [])
        # 長度段的表示應該是位於上面一些的
        if len(p1) > len(p2):
            p1, p2 = p2, p1
        for i in p1:
            if i in p2:
                return TreeNode(i)
        return TreeNode(-1)
"""
符合二叉搜索樹的版本
根據二叉搜索樹的性質(左小右大)
(樹劃分爲:根 左子樹 右子樹)
1. 若是兩個結點位於同一顆子樹上,那麼要麼兩個的值都大於根 or 兩個的值都小於根
2. 若是兩個結點分別位於不一樣的子樹上,那麼其最近的結點必定是根結點
"""
class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        # 同時位於左子樹
        if p.val < root.val and q.val < root.val:
            return self.lowestCommonAncestor(root.left, p, q)
        # 同時位於右子樹
        if p.val > root.val and q.val > root.val:
            return self.lowestCommonAncestor(root.right, p, q)
        # 一個子樹一個,其最近祖先必然是根
        return root

129. 求根到葉子節點數字之和

"""
實質仍是在求二叉樹的全部路徑
Tip: 遞歸的時候保證每次返回的時候不改變參數值
"""
class Solution:
    def sumNumbers(self, root: TreeNode) -> int:
        res = []
        def DFS(root, tmp):
            if not root:
                return
            if not root.left and not root.right:
                res.append((tmp + [str(root.val)]).copy())
                return
            if root.left:
                DFS(root.left, tmp + [str(root.val)])
            if root.right:
                DFS(root.right, tmp + [str(root.val)])
        DFS(root, [])
        s = 0
        for i in res:
            while len(i) != 0 and i[0] == '0':
                i.pop(0)
            if len(i) == 0:
                continue
            s += eval("".join(i))
        return s
相關文章
相關標籤/搜索