代码随想录第16天:(二叉树)
一、最大二叉树(Leetcode 654)
class Solution:
def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
# 基础条件:当数组只有一个元素时,直接返回该元素构建的二叉树节点
if len(nums) == 1:
return TreeNode(nums[0]) # 创建节点并返回
# 创建一个空节点,用来存放最大值
node = TreeNode(0)
# 找到数组中最大的值和对应的下标
maxValue = 0
maxValueIndex = 0
for i in range(len(nums)):
if nums[i] > maxValue: # 比较当前元素是否大于已知的最大值
maxValue = nums[i] # 更新最大值
maxValueIndex = i # 记录最大值的下标
# 将最大值作为根节点
node.val = maxValue
# 处理最大值所在的下标左边的部分,递归构建左子树
if maxValueIndex > 0: # 如果左区间非空
new_list = nums[:maxValueIndex] # 获取最大值左侧的数组
node.left = self.constructMaximumBinaryTree(new_list) # 递归构建左子树
# 处理最大值所在的下标右边的部分,递归构建右子树
if maxValueIndex < len(nums) - 1: # 如果右区间非空
new_list = nums[maxValueIndex+1:] # 获取最大值右侧的数组
node.right = self.constructMaximumBinaryTree(new_list) # 递归构建右子树
# 返回构建好的节点(包括其左右子树)
return node
利用切片+递归:
class Solution:
def constructMaximumBinaryTree(self, nums: List[int]) -> TreeNode:
# 递归终止条件:如果当前数组为空,返回 None,表示没有节点
if not nums:
return None
# 找到当前数组中的最大值,并获取其索引
max_val = max(nums) # 获取数组中的最大值
max_index = nums.index(max_val) # 获取最大值的索引
# 创建一个新的树节点,节点的值为最大值
node = TreeNode(max_val)
# 递归构建左子树:数组中最大值左侧的部分
node.left = self.constructMaximumBinaryTree(nums[:max_index])
# 递归构建右子树:数组中最大值右侧的部分
node.right = self.constructMaximumBinaryTree(nums[max_index+1:])
# 返回当前节点,该节点是一个包含左、右子树的树节点
return node
二、合并二叉树(Leetcode 617)
class Solution:
def mergeTrees(self, root1: TreeNode, root2: TreeNode) -> TreeNode:
# 递归终止条件:
# 但凡有一个节点为空, 就立刻返回另外一个. 如果另外一个也为None就直接返回None.
if not root1:
return root2
if not root2:
return root1
# 上面的递归终止条件保证了代码执行到这里root1, root2都非空.
root = TreeNode() # 创建新节点
root.val += root1.val + root2.val# 中
root.left = self.mergeTrees(root1.left, root2.left) #左
root.right = self.mergeTrees(root1.right, root2.right) # 右
return root
三、二叉搜索树中的搜索(Leetcode 700)
递归法:
class Solution:
def searchBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
# 如果当前节点为空(即树为空)或当前节点的值等于目标值
# 则返回当前节点(即找到了目标值的节点)
if not root or root.val == val:
return root
# 如果当前节点的值大于目标值,则目标值应该在当前节点的左子树中
if root.val > val:
return self.searchBST(root.left, val)
# 如果当前节点的值小于目标值,则目标值应该在当前节点的右子树中
if root.val < val:
return self.searchBST(root.right, val)
迭代法:
class Solution:
def searchBST(self, root: [TreeNode], val: int) -> TreeNode:
# 当当前节点存在时,继续迭代查找
while root:
# 如果当前节点的值大于目标值,目标节点应该在左子树
if root.val > val:
root = root.left
# 如果当前节点的值小于目标值,目标节点应该在右子树
elif root.val < val:
root = root.right
# 如果当前节点的值等于目标值,返回当前节点
else:
return root
# 如果没有找到目标值的节点,返回 None
return None
四、验证二叉搜索树(Leetcode 98)
思路:二叉搜索树的中序遍历结果为递增有序数组
class Solution:
def __init__(self):
self.vec = [] # 用于存储二叉树中序遍历的结果
# 中序遍历二叉树
def traversal(self, root):
if root is None: # 基本条件:如果当前节点为空,则返回
return
self.traversal(root.left) # 递归遍历左子树
self.vec.append(root.val) # 将当前节点的值加入到vec列表中
self.traversal(root.right) # 递归遍历右子树
# 判断是否是有效的二叉搜索树
def isValidBST(self, root):
self.vec = [] # 清空数组
self.traversal(root) # 执行中序遍历,填充vec
# 检查中序遍历的结果是否严格递增
for i in range(1, len(self.vec)):
# 注意要小于等于,搜索树里不能有相同元素
if self.vec[i] <= self.vec[i - 1]: # 如果不严格递增,说明不是有效的BST
return False
return True # 如果遍历完都没有问题,说明是有效的BST
误区:
if (root.val > root.left.val and root.val < root.right.val):
return True
二叉搜索树的根节点比左边所有子树的值都大,比所有右子树的值都要小,上述判断语句没有考虑到整体
迭代法:中序遍历判断结果是否递增
class Solution:
def isValidBST(self, root: Optional[TreeNode]) -> bool:
stack = [] # 初始化栈,用来模拟递归的过程
cur = root # 当前节点指针,从根节点开始遍历
pre = None # 记录前一个节点,初始化为 None
# 当当前节点不是 None,或者栈中还有待处理的节点时继续遍历
while cur or stack:
if cur:
# 如果当前节点不为空,将当前节点压入栈
stack.append(cur)
# 然后访问当前节点的左子树
cur = cur.left
else:
# 如果当前节点为空,弹出栈顶节点并处理
cur = stack.pop() # 弹出栈顶节点
# 如果前一个节点存在,且当前节点的值不大于前一个节点的值,返回 False
if pre and cur.val <= pre.val:
return False
# 更新前一个节点为当前节点
pre = cur
# 访问当前节点的右子树
cur = cur.right
# 如果遍历完成后没有违反 BST 规则,返回 True
return True