python 二叉树总结(二)
对称二叉树
思路:比较根节点的左右子树是否翻转
递归做法:1. 先判断None的情况 2.然后判断左右节点数值的情况
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if not root:
return None
return self.comper(root.left, root.right)
def comper(self, left, right):
if left == None and right != None: return False
elif left != None and right == None: return False
elif left == None and right == None : return True
elif left.val != right.val: return False
else:
outside = self.comper(left.left, right.right)
inside = self.comper(left.right, right.left)
is_same = outside and inside
return is_same
迭代法:用队列
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if not root:
return None
from collections import deque
que = deque([root.left, root.right])
while que:
first_node = que.popleft()
second_node = que.popleft()
if not first_node and not second_node:
continue
if not first_node or not second_node or first_node.val != second_node.val:
return False
que.append(first_node.left)
que.append(second_node.right)
que.append(first_node.right)
que.append(second_node.left)
return True
迭代: 用栈
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
if not root:
return None
stack = [root.right, root.left]
while stack:
left_node = stack.pop()
right_node = stack.pop()
if not left_node and not right_node:
continue
if not left_node or not right_node or left_node.val != right_node.val:
return False
stack.append(left_node.right)
stack.append(right_node.left)
stack.append(right_node.right)
stack.append(left_node.left)
return True
完全二叉树节点
普通二叉树求节点:
递归解法:
class Solution:
def countNodes(self, root: TreeNode) -> int:
if not root:
return 0
return self.getNodeSum(root)
def getNodeSum(self, node):
if not node:
return 0
left_sum = self.getNodeSum(node.left)
right_sum = self.getNodeSum(node.right)
return left_sum + right_sum + 1 # 加一是中间节点
迭代
class Solution:
def countNodes(self, root: TreeNode) -> int:
if not root:
return 0
result = 0
from collections import deque
que = deque([root])
while que:
node = que.pop()
result += 1
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
return result
完全二叉树的解法:
# 递归:
class Solution:
def countNodes(self, root: TreeNode) -> int:
if not root:
return 0
left = root.left
right = root.right
left_high = 1
right_high = 1
while left:
left = left.left
left_high += 1
while right:
right = right.right
right_high += 1
if left_high == right_high:
tree_sum = 2 ** left_high - 1
return tree_sum
return self.countNodes(root.left) + self.countNodes(root.right) + 1
平衡二叉树
# 递归
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
if self.get_high(root) != -1:
return True
else:
return False
def get_high(self, node):
if not node:
return 0
left_high = self.get_high(node.left)
right_high = self.get_high(node.right)
if left_high == -1 or right_high == -1:
return -1
if abs(left_high - right_high) > 1:
return -1
return 1 + max(left_high, right_high)
# 迭代法:
class Solution:
def isBalanced(self, root: TreeNode) -> bool:
if not root:
return True
stack = [root]
while stack:
node = stack.pop()
if abs(self.get_depth(node.left) - self.get_depth(node.right)) > 1:
return False
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
return True
def get_depth(self, root):
if not root:
return 0
depth = 0
from collections import deque
que = deque([root])
while que:
size = len(que)
depth += 1
for _ in range(size):
node = que.popleft()
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
return depth
二叉树的所有路径
# 递归
class Solution:
def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
if not root:
return []
result = []
path = ''
self.traversal(root, path, result)
return result
def traversal(self, node, path, result):
path += str(node.val)
if not node.left and not node.right:
result.append(path)
if node.left:
self.traversal(node.left, path + '->', result)
if node.right:
self.traversal(node.right, path + '->', result)
# 迭代法:
class Solution:
def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
if not root:
return []
node_stack = deque([root])
path_stack = deque([])
result = []
path_stack.append(str(root.val))
while node_stack:
node = node_stack.popleft()
path = path_stack.popleft()
if not node.left and not node.right:
result.append(path)
if node.right:
node_stack.append(node.right)
path_stack.append(path + '->' + str(node.right.val))
if node.left:
node_stack.append(node.left)
path_stack.append(path + '->' + str(node.left.val))
return result
相同的树
class Solution:
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
return self.is_same(p, q)
def is_same(self, tree1, tree2):
if not tree1 and tree2: return False
elif tree1 and not tree2: return False
elif not tree1 and not tree2: return True
elif tree1.val != tree2.val: return False
else:
comper_left = self.is_same(tree1.left, tree2.left)
comper_right = self.is_same(tree1.right, tree2.right)
comper = comper_left and comper_right
return comper
左叶子之和
# 递归:
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
if not root: return 0
left_tree_left_levels_sum = self.sumOfLeftLeaves(root.left)
rirht_tree_left_levels_sum = self.sumOfLeftLeaves(root.right)
levels_sum = 0
if root.left and not root.left.left and not root.left.right:
levels_sum = root.left.val
return left_tree_left_levels_sum + rirht_tree_left_levels_sum + levels_sum
# 迭代:
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
if not root: return 0
stack = [root]
res = 0
while stack:
node = stack.pop()
if node.left and not node.left.left and not node.left.right:
res += node.left.val
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)
return res
找树左下角的值
class Solution:
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
if not root:
return None
from collections import deque
que = deque([root])
while que:
_len = len(que)
for i in range(_len):
node = que.popleft()
if i == 0:
result = node.val
if node.left:
que.append(node.left)
if node.right:
que.append(node.right)
return result
路径总和i
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root:
return False
path = ''
result = []
self.traversal(root, path, result)
if targetSum in result:
return True
else:
return False
def traversal(self, node, path, result):
path += str(node.val)
if not node.left and not node.right:
result.append(sum(list(map(int, path.split('->')))))
if node.left:
self.traversal(node.left, path + '->', result)
if node.right:
self.traversal(node.right, path + '->', result)
总数之和ii
class Solution:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
if not root:
return []
path = ''
result = []
res = []
self.traversal(root, path, result)
for i in range(len(result)):
way = list(map(int, result[i].split('->')))
if sum(way) == targetSum:
res.append(way)
return res
def traversal(self, node, path, result):
path += str(node.val)
if not node.left and not node.right:
result.append(path)
if node.left:
self.traversal(node.left, path + '->', result)
if node.right:
self.traversal(node.right, path + '->', result)
从中序和后序遍历序列构造二叉树
class Solution:
def buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
if not inorder:
return None
head_val = postorder[-1]
root = TreeNode(head_val)
root_index = inorder.index(head_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
从前序和中序遍历构造二叉树
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
if not preorder:
return None
head_val = preorder[0]
root = TreeNode(head_val)
root_index = inorder.index(head_val)
root.left = self.buildTree(preorder[1: root_index + 1], inorder[: root_index])
root.right = self.buildTree(preorder[root_index + 1: ], inorder[root_index + 1: ])
return root
最大二叉树
class Solution:
def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
if not nums:
return None
_max = max(nums)
max_index = nums.index(_max)
root = TreeNode(_max)
root.left = self.constructMaximumBinaryTree(nums[:max_index])
root.right = self.constructMaximumBinaryTree(nums[max_index + 1: ])
return root
合并二叉树
# 递归:
class Solution:
def mergeTrees(self, root1, root2):
if not root1 and not root2:
return None
if root1 and not root2:
return root1
elif not root1 and root2:
return root2
else:
root_val = root1.val + root2.val
root = TreeNode(root_val)
root.left = self.mergeTrees(root1.left, root2.left)
root.right = self.mergeTrees(root1.right, root2.right)
return root
迭代:注释下面的写法更简洁
class Solution:
def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
# if not root1 and not root2:
# return None
# if root1 and not root2:
# return root1
# elif not root1 and root2:
# return root2
# else:
# que = deque([root1, root2])
if not root1:
return root2
if not root2:
return root1
que = deque([root1, root2])
while que:
node1 = que.popleft()
node2 = que.popleft()
if node1.left and node2.left:
que.append(node1.left)
que.append(node2.left)
if node1.right and node2.right:
que.append(node1.right)
que.append(node2.right)
node1.val += node2.val
if not node1.left and node2.left:
node1.left = node2.left
if not node1.right and node2.right:
node1.right = node2.right
return root1
二叉搜索树
迭代:
class Solution:
def searchBST(self, root: TreeNode, val: int) -> TreeNode:
if not root:
return None
cur = root
while cur:
if cur.val == val: return cur
elif cur.val > val: cur = cur.left
else: cur = cur.right
return None
# 递归:
class Solution:
def searchBST(self, root: TreeNode, val: int) -> TreeNode:
if not root:
return None
if root.val == val: return root
# 注意这里要加 return,当要搜索某条边或者某个节点时,需要加return, 不然就是遍历整棵树
elif root.val > val:
return self.searchBST(root.left, val)
else:
return self.searchBST(root.right, val)
验证二叉搜索树
不能只判断当前节点的左节点小于根节点,右节点大于根节点,而是整个左子树小于根节点,整个柚子树大于根节点
可以用中序遍历二叉数存到数组中,判断数组是否有序。
# 利用中序遍历将值放到数组中
# 这串代码一开始发现没有全部A出来,结果显示result和result_sort是一样的但是返回的是False,找不到原因
# 后来发现是这题要求二叉搜索树中值不能重复
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
if not root:
return
result = []
self.traversal(root, result)
result_sort = sorted(result)
if len(result) == len(set(result)):
if result == result_sort:
return True
return False
def traversal(self, node, result):
if not node:
return
self.traversal(node.left, result)
result.append(node.val)
self.traversal(node.right, result)
# 标准做法:迭代
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
if not root:
return True
stack = []
cur = root
pre = None
while cur or stack:
if cur:
stack.append(cur)
cur = cur.left
else:
node = stack.pop()
cur = node
if pre and cur.val <= pre.val:
return False
pre = cur
cur = cur.right
return True
二叉搜索树的最小绝对值
class Solution:
def getMinimumDifference(self, root: TreeNode) -> int:
if not root:
return None
result = []
self.buildlist(root, result)
_min = []
for i in range(1, len(result)):
_min.append(result[i] - result[i - 1])
return min(_min)
def buildlist(self, node, result):
if not node:
return
self.buildlist(node.left, result)
result.append(node.val)
self.buildlist(node.right, result)
二叉搜索树的众数
普通二叉树的做法:
- 把树遍历
- 用map统计频率,把频率排个序
- 取前面高频的元素集合
二叉搜索树做法:双指针
- 弄一个指针指向前一个节点,每次cur(当前节点)才能和pre(前一个节点)作比较
- 初始化的时候 pre= NULL,这样当pre为NULL时,就知道这是比较的第一个元素
- 用评率count记录元素出现频率,如果等于maxCount,就把这个元素加到结果集中
- 如果这个maxCount不是最大频率,就让之前的元素失效
递归:
class Solution:
def findMode(self, root: TreeNode) -> List[int]:
self.result = []
self.max_count = 0
self.count = 0
self.pre = TreeNode()
self.searchBST(root)
return self.result
def searchBST(self, node):
if not node:
return None
self.searchBST(node.left) # 左
# 中
if not self.pre:
self.count = 1
elif self.pre.val == node.val:
self.count += 1
else:
self.count = 1
self.pre = node
if self.count == self.max_count:
self.result.append(node.val)
elif self.count > self.max_count:
self.result = [node.val]
self.max_count = self.count
self.searchBST(node.right) # 右
# 迭代-中序遍历-不使用额外的空间,利用搜索二叉树的特性
class Solution:
def findMode(self, root: TreeNode) -> List[int]:
stack = []
count, max_count = 0, 0
result = []
cur = root
pre = TreeNode()
while cur or stack:
if cur: # 指针来访问节点,访问到最底层
stack.append(cur)
cur = cur.left
else: # 逐一处理节点
cur = stack.pop()
if not pre:
count = 1
elif pre.val == cur.val: # 与前一个节点数值相同
count += 1
else:
count = 1
if count == max_count:
result.append(cur.val)
elif count > max_count:
result = [cur.val]
max_count = count
pre = cur
cur = cur.right
return result
最近公共祖先
# 递归回溯
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root or root == q or root == p:
return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if left and right:
return root
if left:
return left
return right
二叉搜索树的最近公共祖先
从上到下找到第一个在p, q区间的数
# 递归:
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)
if root.val < p.val and root.val < q.val:
return self.lowestCommonAncestor(root.right, p, q)
return root
# 迭代:
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
while True:
if root.val > p.val and root.val > q.val:
root = root.left
elif root.val < p.val and root.val < q.val:
root = root.right
else:
return root
二叉搜索树的插入操作
# 递归:有返回值
class Solution:
def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
if not root:
return TreeNode(val)
# 这里返回的直接就是新的树
if val < root.val:
root.left = self.insertIntoBST(root.left, val)
if val > root.val:
root.right = self.insertIntoBST(root.right, val)
return root
# 递归:无返回值
class Solution:
def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
if not root:
return TreeNode(val)
if not root.left and val < root.val:
root.left = TreeNode(val)
if not root.right and val > root.val:
root.right = TreeNode(val)
if val < root.val:
self.insertIntoBST(root.left, val)
if val > root.val:
self.insertIntoBST(root.right, val)
return root
迭代;
class Solution:
def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
if not root:
return TreeNode(val)
parent = None
cur = root
while cur:
if val < cur.val:
parent = cur
cur = cur.left
else:
parent = cur
cur = cur.right
if val < parent.val:
parent.left = TreeNode(val)
else:
parent.right = TreeNode(val)
return root
删除二叉搜索树的节点
普通二叉树删除方式:用交换值的操作来删除目标节点
代码中目标节点被操作两次:
- 第一次是和目标节点的右子树最左面节点交换
- 第二次直接被NULL覆盖
搜索二叉树删除节点五种情况:
- 没有找到节点,遍历到空节点返回
- 找到节点,左右孩子都为空,直接删除节点,返回None
- 删除节点的左孩子为空,右孩子不为空,返回右孩子根节点
- 删除节点的右孩子为空,左孩子不为空,返回左孩子根节点
- 左右孩子节点都不为空,将删除节点的左子树根节点放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点
class Solution:
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
if not root: return root
if root.val == key:
if not root.left and not root.right: return None
elif not root.left:
tmp = root
root = root.right
del tmp
return root
elif not root.right:
tmp = root
root = root.left
del tmp
return root
else:
v = root.right
while v.left:
v = v.left
tmp = root
v.left = root.left
root = root.right
del tmp
return root
if root.val > key:
root.left = self.deleteNode(root.left, key)
if root.val < key:
root.right = self.deleteNode(root.right, key)
return root
修剪二叉搜索树![在这里插入图片描述](https://img-blog.csdnimg.cn/ab3f3fde329c43f2b4276aead67252c8.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAVHJhdmlzbGdk,size_20,color_FFFFFF,t_70,g_se,x_16)
将节点2直接赋值给3
class Solution:
def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
if not root: return None
# 单层递归逻辑
if root.val < low:
return self.trimBST(root.right, low, high)
# 若当前root节点小于左界:只考虑其右子树,用于替代更新后的其本身,抛弃其左子树整体
if root.val > high:
return self.trimBST(root.left, low, high)
# 若当前root节点大于右界:只考虑其左子树,用于替代更新后的其本身,抛弃其右子树整体
if low <= root.val <= high:
root.left = self.trimBST(root.left, low, high)
root.right = self.trimBST(root.right, low, high)
# 返回更新后的剪枝过的当前节点root
return root
将有序数组转换成二叉搜索树
构造二叉树:重点是选取数组最中间元素为分割点,左侧为递归的左区间,右侧为递归的右区间,必然是平衡树,左闭右闭区间。
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
if not nums: return None
root = self.traversal(nums, 0, len(nums) - 1)
return root
def traversal(self, nums, left, right):
if left > right: return None
mid = left + (right - left) // 2
root = TreeNode(nums[mid])
root.left = self.traversal(nums, left, mid - 1)
root.right = self.traversal(nums, mid + 1, right)
return root
把二叉搜索树转换为累加树
class Solution:
def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root: return None
self.pre = 0
self.traversal(root)
return root
def traversal(self, node):
if not node:
return None
self.traversal(node.right)
self.pre += node.val
node.val = self.pre
self.traversal(node.left)