Leetcode题解 - 树部分简单题目代码+思路(105、106、109、112、897、257、872、226、235、129)
树的题目中递归用的比较多(但是递归是真难弄 我🍂了,这次也忘记加上题目了,下次注意🤥
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