樹的題目中遞歸用的比較多(可是遞歸是真難弄 我🍂了,此次也忘記加上題目了,下次注意🤥node
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
""" 遞歸構造, 中序遍歷爲左根右,後序遍歷爲左右根。 每次找到根的位置再遞歸去構建左右子樹。 """ 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. 有序鏈表轉換二叉搜索樹 """ 將鏈表想象成一根繩子,每次都抓住最中間的部分做爲根,遞歸實現。(相似於中序、後序還原一顆樹) """ 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)
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)
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
""" 想不出來遞歸就想特殊狀況: ` 空樹如何處理 ` 只有一個根節點的如何處理 ` 有一個根節點一個左節點一個右節點的如何處理 """ 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]
""" 一開始考慮的是利用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
""" 根不變,左子樹變成右子樹,右子樹變成左子樹。 """ 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
""" 並無用到題中給出的二叉搜索樹的良好性質。 先記錄每個節點的父節點,再從目標節點一直走到根節點,判斷兩個目標節點走到根節點路徑中重合的第一個點 """ 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
""" 實質仍是在求二叉樹的全部路徑 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