二叉树的主要解法就是递归,DFS深度优先搜索。
这里记录不太熟的题
226.翻转二叉树
先序遍历:根左右
翻转一个二叉树,首先要考虑根节点的左右子节点,将其替换。(根)
然后继续翻转左子树。dfs,左
翻转右子树。右
python
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
def dfs(node):
if not node:
return
# 根
node.left,node.right = node.right,node.left
# 左,右
node.left = dfs(node.left)
node.right = dfs(node.right)
return node
return dfs(root)
101. 对称二叉树
考虑先序遍历
逐层看同一层的两个节点是否对称:都为空; 如果说只有一个为空或者不相等,那就是不对称
根:对根节点和左右子节点判断是否对称
左右:下一层的子节点,也就是左子节点的左边和右子节点的右边以及另外一对是否都通过验证
python
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
def dfs(left,right):
if not left and not right:
return True
if not left or not right:
return False
if left.val != right.val:
return False
return dfs(left.left, right.right) and dfs(left.right, right.left)
return dfs(root.left, root.right)
104. 二叉树的最大深度
后序遍历
最大深度就是左右子树中取最大深度+1
先检查左右子树,然后在基础上+1
python
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
def dfs(root):
if not root:
return 0
left = dfs(root.left)
right = dfs(root.right)
return max(left,right)+1
return dfs(root)
111. 二叉树的最小深度
后序遍历
跟最大的区别在于要考虑左右子树是否为空的情况,如果为空,就要返回另一个子树的深度+1
python
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
#根左右,
def dfs(root):
if not root:
return 0
left = dfs(root.left)
right = dfs(root.right)
if not root.left:
return right+1
if not root.right:
return left+1
return min(left,right)+1
return dfs(root)
222.完全二叉树的节点个数
后序遍历
分别求左右子树的节点数,然后加上根节点
python
class Solution:
def countNodes(self, root: Optional[TreeNode]) -> int:
def dfs(root):
if not root:
return 0
left = dfs(root.left)
right = dfs(root.right)
return left+right+1
return dfs(root)
110. 平衡二叉树
要求任意节点的左右子树的高度差小于等于1
后序遍历
先计算左右子树的高度
然后在跟节点这判断是否平衡,如果不平衡就返回-1,否则返回高度用于上一层的计算
最后看最终返回的是-1还是高度,是-1就不平衡
python
class Solution:
def isBalanced(self, root: Optional[TreeNode]) -> bool:
def dfs(root):
if not root:
return 0
left = dfs(root.left)
right = dfs(root.right)
if abs(left-right) > 1 or left == -1 or right == -1:
return -1
else:
return max(left,right)+1
return dfs(root) != -1
257. 二叉树的所有路径
先序遍历
回溯
先加上根节点,然后在左右节点上递归。视作一个list,最后转换为字符串
回溯终止条件:叶子节点,也就是没有左右子节点
python
class Solution:
def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
res = []
path = [str(root.val)]
def bc(root,path):
if not root.left and not root.right:
res.append(path[:])
return
if root.left:
bc(root.left,path+[str(root.left.val)])
if root.right:
bc(root.right,path+[str(root.right.val)])
bc(root,path)
return ["->".join(i) for i in res]
404. 左叶子之和
先序遍历
分别找左右子树的左叶子节点
递归终止条件:没有该节点,到了叶子节点,直接返回0
左子树的左叶子节点需要判断下面是否还有左叶子节点
python
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
def dfs(root):
# 终止条件
if not root:
return 0
if not root.left and not root.right:
return 0
left = dfs(root.left)
if root.left and not root.left.left and not root.left.right:
left = root.left.val
right = dfs(root.right)
return left+right
return dfs(root)
513. 找树左下角的值
层序遍历,广度优先搜索BFS
遍历每层时将第一个节点作为所求,直到层序遍历结束。
python
from collections import deque
from typing import Optional
# Definition for a binary tree node.
class TreeNode:
def __init__(self, val=0, left: Optional['TreeNode']=None, right: Optional['TreeNode']=None):
self.val = val
self.left = left
self.right = right
class Solution:
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
if not root:
return None # 或者根据题目要求返回其他值
queue = deque([root])
bottom_left = root.val # 初始化为根节点值
while queue:
level_size = len(queue)
for i in range(level_size):
node = queue.popleft()
# 在遍历每层时,第一个节点是最左边的
if i == 0:
bottom_left = node.val
# 先添加左子节点,再添加右子节点
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return bottom_left
112. 路径总和
先序遍历+回溯
终止条件:叶子节点且达到目标值
返回值:布尔值
每次进入就减去当前节点值
python
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root:
return False
def bc(root, targetSum):
# 终止条件
if not root.left and not root.right and targetSum == 0:
return True
# 递归,左子树
if root.left: # 看左子树是否是
if bc(root.left, targetSum-root.left.val):
return True
if root.right:
if bc(root.right, targetSum-root.right.val):
return True
return False
return bc(root, targetSum-root.val)
106. 从中序与后序遍历序列构造二叉树
中序:左根右
后序:左右根
思路:先确定根节点,然后递归确定左右子树的根节点,逐步联系起来即可
要确定的是左右子树的list切片范围,用index函数得到
python
class Solution:
def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
if not postorder:
return
root = TreeNode(postorder[-1])
root_index = inorder.index(root.val)
root.left = self.buildTree(inorder[:root_index], postorder[:root_index])
root.right = self.buildTree(inorder[root_index+1:], postorder[root_index:-1])
return root
654. 最大二叉树
上题的简化版,根节点是最大值
python
class Solution:
def constructMaximumBinaryTree(self, nums: List[int]) -> Optional[TreeNode]:
if not nums:
return
val = max(nums)
root = TreeNode(val)
index = nums.index(val)
root.left = self.constructMaximumBinaryTree(nums[:index])
root.right = self.constructMaximumBinaryTree(nums[index+1:])
return root
617. 合并二叉树
如果有一方为空,那就直接返回另一个就行
都有值,就正常计算
跟上面的一脉相承
python
class Solution:
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
if not root1:
return root2
if not root2:
return root1
root = TreeNode(root1.val + root2.val)
root.left = self.mergeTrees(root1.left, root2.left)
root.right = self.mergeTrees(root1.right, root2.right)
return root
700. 二叉搜索树中的搜索
搜索树,左子树小于根节点 ,右子树大于根节点
先序遍历+递归+二分查找
python
class Solution:
def searchBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
if not root: return
if root.val == val:
return root
elif root.val < val:
return self.searchBST(root.right, val)
else:
return self.searchBST(root.left,val)
98. 验证二叉搜索树
先序遍历,要同时满足左右子树都OK
辅助函数
python
class Solution:
def isValidBST(self, root: Optional[TreeNode]) -> bool:
def valid(root, low, high):
if not root:
return True
if not (low < root.val < high):
return False
return valid(root.left, low, root.val) and valid(root.right, root.val, high)
return valid(root, float("-inf"), float("inf"))
530. 二叉搜索树的最小绝对差
最小差肯定是相邻的两个节点的,采用中序遍历,要有两个变量指示前个和当前节点
使用栈保存中序遍历的结果,左子树遍历完后找根节点进行计算,然后是右子树
python
class Solution:
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
# 初始化前一个节点的值为负无穷大
pre = float("-inf")
# 当前节点初始化为根节点
cur = root
# 使用栈来辅助中序遍历
stack = []
# 初始化最小差值为正无穷大
res = float("inf")
# 当当前节点不为空或栈不为空时,继续遍历
while cur or stack:
# 一直向左遍历,直到到达最左下的节点
while cur:
stack.append(cur) # 将当前节点压入栈中
cur = cur.left # 移动到左子节点
# 弹出栈顶节点,即当前层的最左节点
cur = stack.pop()
# 计算当前节点值与前一个节点值的差,并更新最小差值
res = min(res, cur.val - pre)
# 更新前一个节点值为当前节点值
pre = cur.val
# 移动到右子节点,继续遍历
cur = cur.right
# 返回最终的最小绝对差值
return res
236. 二叉树的最近公共祖先
先序遍历
如果有一个是根节点,那就是根节点
左右子树遍历,查看里面是否有目标
如果都遇到目标,那就是根节点;否则,选择存在的
python
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if p == root or q == root or not root:
return root
left = self.lowestCommonAncestor(root.left, p,q)
right = self.lowestCommonAncestor(root.right, p,q)
if left and right:
return root
if not left:
return right
if not right:
return left
235. 二叉搜索树的最近公共祖先
跟上题的区别在于二叉搜索可以用二分查找的思想
先序遍历:根,左,右
python
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if root.val > p.val and root.val > q.val:
return self.lowestCommonAncestor(root.left,p,q)
elif root.val < p.val and root.val < q.val:
return self.lowestCommonAncestor(root.right,p,q)
else:
return root
701. 二叉搜索树中的插入操作
先序遍历
左右子树联系起来
python
class Solution:
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
if not root:
return TreeNode(val)
if root.val > val:
root.left = self.insertIntoBST(root.left, val)
if root.val < val:
root.right = self.insertIntoBST(root.right, val)
return root