669. 修剪二叉搜索树
难度:☆4
本题修剪和重构二叉搜索树的思路容易想得很复杂,实际代码实现很简洁。
a. 递归法
单层递归的逻辑:如果 root
(当前节点)的值小于 low
,那么应该递归右子树,并返回右子树符合条件的头节点。如果 root
(当前节点)的值大于 high
,那么应该递归左子树,并返回左子树符合条件的头节点。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
if not root:
return None
if root.val < low: # 若root小于low,只考虑其右子树,用于替代更新后的其本身,抛弃其左子树整体
return self.trimBST(root.right, low, high)
if root.val > high: # 若root大于high,只考虑其左子树,用于替代更新后的其本身,抛弃其右子树整体
return self.trimBST(root.left, low, high)
root.left = self.trimBST(root.left, low, high)
root.right = self.trimBST(root.right, low, high)
return root
108. 将有序数组转换为二叉搜索树
难度:☆4
如果没有限定构造高度平衡的二叉搜索树,则将有序数组直接串联成线性链表,也是一棵二叉搜索树,但没有考察意义。
解题思路是每次取中间节点做父节点,类似二分法、分而治之。
a. 递归法
注意循环不变量,区间范围用 left
和 right
索引限定,左闭右开或左闭右闭均可。
取中间位置,以中间位置的元素构造节点。接着划分区间,root
的左孩子接住下一层左区间构造的节点,右孩子接住下一层右区间构造的节点。最后返回 root
节点。
- 左闭右开区间。
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
return self.traversal(nums, 0, len(nums)) # 左闭右开
def traversal(self, nums: List[int], left: int, right: int) -> Optional[TreeNode]:
if left >= right: # 左闭右开
return None
mid = left + (right - left) // 2 # 防止整数越界
root = TreeNode(nums[mid])
root.left = self.traversal(nums, left, mid)
root.right = self.traversal(nums, mid+1, right)
return root
- 左闭右闭区间。
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
return self.traversal(nums, 0, len(nums)-1) # 左闭右闭
def traversal(self, nums: List[int], left: int, right: int) -> Optional[TreeNode]:
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
538. 把二叉搜索树转换为累加树
难度:☆3
本题要求的累加顺序,正好是二叉树的反向中序遍历:右中左,然后利用前后双指针,顺序累加就可以了。
a. 递归法:反向中序遍历+双指针
利用递归法和前后双指针实现反向中序遍历。注意 pre
只需要记录前一个节点的值即可,记录节点会麻烦。
class Solution:
def __init__(self):
self.pre = 0 # 记录前一个节点的值
def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
self.inverseInorder(root)
return root
def inverseInorder(self, cur: Optional[TreeNode]) -> None:
if not cur:
return
self.inverseInorder(cur.right) # 右
cur.val += self.pre # 中
self.pre = cur.val
self.inverseInorder(cur.left) # 左
b. 迭代法:反向中序遍历+双指针
利用栈模拟递归过程,借助前后双指针,实现反向中序遍历。注意 pre
只需要记录前一个节点的值即可,记录节点会麻烦。
class Solution:
def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
stack = []
cur = root
pre = 0 # 记录前一个节点的值
while cur or stack:
if cur: # 一直访问到最底层
stack.append(cur)
cur = cur.right # 右
else:
cur = stack.pop() # 中
cur.val += pre
pre = cur.val
cur = cur.left # 左
return root