106.从中序与后序遍历序列构造二叉树
给定两个整数数组 inorder
和 postorder
,其中 inorder
是二叉树的中序遍历, postorder
是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
手动构造的步骤:
后序确定根,中序分左右(子树)。
以 后序数组的最后一个元素(根)为切割点,先切中序数组,根据中序数组,反过来再切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。
class Solution:
def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
def traversal(inorder, postorder):
if not postorder:
return None
# 根
rootValue = postorder[-1]
root = TreeNode(rootValue)
# 叶子
if len(postorder) == 1:
return root
#3. 找切割点
inorder_index = inorder.index(rootValue)
# 4. 切割 inorder 左、右
leftInorder = inorder[:inorder_index]
rightInorder = inorder[inorder_index+1:]
# 5. 切割 postoder 左、右
postorder = postorder[:-1]
leftPostorder = postorder[:len(leftInorder)]
rightPostorder = postorder[len(leftInorder):]
# 6. 递归处理
root.left = traversal(leftInorder, leftPostorder)
root.right = traversal(rightInorder, rightPostorder)
return root
if len(inorder) == 0 or len(postorder)==0:
return None
root = traversal(inorder, postorder)
return root
654.最大二叉树
给定一个不重复的整数数组 nums
。 最大二叉树 可以用下面的算法从 nums
递归地构建:
- 创建一个根节点,其值为
nums
中的最大值。 - 递归地在最大值 左边 的 子数组前缀上 构建左子树。
- 递归地在最大值 右边 的 子数组后缀上 构建右子树。
返回 nums
构建的 最大二叉树
递归公式:
- 函数参数和返回值
参数:待构建数组nums。
返回值:通过nums构建的树的根节点root - 终止条件
nums为空,无法继续构建。 - 单层逻辑
按照题目的描述。选出最大值,递归左右子树。
class Solution:
def constructMaximumBinaryTree(self, nums: List[int]) -> Optional[TreeNode]:
def construct(nums):
if not nums:
return None
max_value = max(nums)
max_index = nums.index(max_value)
root = TreeNode(max_value)
left_nums = nums[:max_index]
right_nums = nums[max_index+1:]
root.left = construct(left_nums)
root.right = construct(right_nums)
return root
return construct(nums)
(可以优化一下参数,每次不用传nums,而是传数组的左右边界)
617.合并二叉树
合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。
递归公式:
- 函数参数和返回值
参数:两棵树的节点 t1, t2
返回值:合并后的节点 - 终止条件:
t1,t2其中一个为None,则直接返回另一个。 - 单层逻辑
(t1,t2都不为None),两个节点值相加,并递归左右子树。
class Solution:
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
def helper(t1, t2):
if t1 is None:
return t2
if t2 is None:
return t1
t1.val += t2.val
t1.left = helper(t1.left, t2.left)
t1.right = helper(t1.right, t2.right)
return t1
return helper(root1, root2)
700.二叉搜索树中的搜索
在二叉搜索树中找值为val的节点。
利用二叉树的性质(左<根<右)
递归公式:
- 参数:当前节点t。 返回值:节点或None
- 终止条件:t为空
- 单层逻辑:t.val == val,返回。t.val < val ,递归右子树。t.val > val ,递归左子树。
class Solution:
def searchBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
def helper(t):
if t is None:
return None
if t.val == val:
return t
if t.val < val:
return helper(t.right)
else:
return helper(t.left)
return helper(root)
98.验证二叉搜索树
利用二叉树的性质(左<根<右),中序遍历的结果是一个递增的序列。
class Solution:
def isValidBST(self, root: Optional[TreeNode]) -> bool:
def inorder(t):
if t is None:
return
inorder(t.left)
nums.append(t.val)
inorder(t.right)
nums = []
inorder(root)
return all(nums[i]<nums[i+1] for i in range(len(nums)-1))
530.二叉搜索树的最小绝对差
给你一个二叉搜索树的根节点 root
,返回 树中任意两不同节点值之间的最小差值 。
上面说过,二叉搜索树的中序遍历是一个递增 的,所以差值最小的两个节点一定是在中序遍历过程的相邻的两个节点。
class Solution:
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
def inorder(t):
if t is None:
return
inorder(t.left)
nums.append(t.val)
inorder(t.right)
nums = []
inorder(root)
return min(nums[i+1] - nums[i] for i in range(len(nums) - 1) )
501.二叉搜索树中的众数
给你一个含重复值的二叉搜索树(BST)的根节点 root
,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。
假定 BST 满足如下定义:
- 结点左子树中所含节点的值 小于等于 当前节点的值
- 结点右子树中所含节点的值 大于等于 当前节点的值
- 左子树和右子树都是二叉搜索树
class Solution:
def findMode(self, root: Optional[TreeNode]) -> List[int]:
def inorder(t):
if t is None:
return
yield from inorder(t.left)
yield t.val
yield from inorder(t.right)
nums = inorder(root)
res = []
max_times = 1
cur_times = 1
pre = -10**6
for i, num in enumerate(nums):
if num == pre:
cur_times += 1
else:
pre = num
cur_times = 1
if cur_times > max_times:
max_times = cur_times
res = [num]
elif cur_times == max_times:
res.append(num)
return res
236. 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
我们希望从下往上找两个节点的最近公共祖先,那么二叉树的后序遍历(左右中)就可以实现从下到上的顺序。
递归公式:
- 函数参数:当前节点root, 需要匹配的节点p, q
返回值:如果当前节点是p/q祖先,则返回该节点。如果返回值为空,则表示没找到。 - 终止条件:
当前节点为空或则和p/q匹配,则返回root。 - 单层逻辑
递归处理left和right。
如果left和right都不为空,则root为最近公共祖先。
如果left和right只有一个不为空,则返回不为空的那个。
如果left和right都为空,则返回None。
class Solution:
def lowestCommonAncestor(self, root, p, q):
if root == q or root == p or root is None:
return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if left and right:
return root
if left is None and right:
return right
elif left and right is None:
return left
else:
return None
235. 二叉搜索树的最近公共祖先
这次找最近公共祖先可以从上到下找了。因为二叉搜索树满足(左<根<右),所以如果root的值在p,q之间,则说明root是p,q的公共祖先(并且是最近的)。
递归公式:
- 参数:当前节点t
返回值:当前节点t - 终止条件:当前节点为None
- 单层逻辑:如果 t.val 比p,q的值都小,则说明该去右子树找;
如果 t.val 比p,q的值都大,则说明该去左子树找;
否则说明t就是p,q的分叉点,p,q一个在左,一个在右,t就是p,q的最近公共祖先,返回t。
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
def helper(t):
if t is None:
return
if t.val > p.val and t.val > q.val:
return helper(t.left)
elif t.val < p.val and t.val < q.val:
return helper(t.right)
else:
return t
return helper(root)
701.二叉搜索树中的插入操作
给定二叉搜索树(BST)的根节点 root
和要插入树中的值 value
,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。
在二叉树找到空节点插入新数据,不需要调整二叉树结构。
递归公式:
- 参数:当前节点root,待插入的值val
返回值:root - 终止条件:root 为None,创建值为val的节点node并返回node
- 单层逻辑:
if root.val > val
, 递归左子树root.left = self.insertIntoBST(root.left, val)
if root.val < val
, 递归右子树root.right = self.insertIntoBST(root.right, val)
返回root
class Solution:
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
if not root:
node = TreeNode(val)
return node
if root.val > val:
root.left = self.insertIntoBST(root.left, val)
if root.val < val:
root.right = self.insertIntoBST(root.right, val)
return root
450.删除二叉搜索树中的节点
删除二叉搜索树的节点,需要调整树的结构。
递归公式:
- 函数参数: 当前节点root, 待插入值key。
返回值:返回删除后节点后的根节点。 - 终止条件: 当前节点为空,返回None
- 单层逻辑
3.1 如果找到节点(if root.val == key
),删除节点并调整结构。
3.2 没找到节点,则递归查找。
if root.val > key:
root.left = self.deleteNode(root.left, key)
if root.val < key:
root.right = self.deleteNode(root.right, key)
3.3 返回root
其中3.1 删除节点可能遇到多种情况:
- 当前节点没有子节点了,直接删除,返回None
- 当前节点只有单侧节点(左/右),直接删除,返回左/右节点
- 左右节点都有,需要将左子树挂在右子树的最左下角,然后删除节点,返回右节点。
(不需要显式删除节点)
class Solution:
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
if root is None:
return None
if root.val == key:
if root.left is None and root.right is None:
return None
elif root.left is None:
return root.right
elif root.right is None:
return root.left
else: # 左右都不为空时, 将 左子树 挂在右子树的最左下角
cur = root.right
while cur.left :
cur = cur.left
cur.left = root.left
return root.right
if root.val > key:
root.left = self.deleteNode(root.left, key)
if root.val < key:
root.right = self.deleteNode(root.right, key)
return root
669. 修剪二叉搜索树
给你二叉搜索树的根节点 root
,同时给定最小边界low
和最大边界 high
。通过修剪二叉搜索树,使得所有节点的值在[low, high]
中。
class Solution:
def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
def helper(t):
# 终止条件
if t is None:
return None
# 单层逻辑
# 1.如果根<low,则(删除根和左孩子),处理右孩子并返回
if t.val < low:
right = helper(t.right)
return right
# 2.同理,如果根>high,则(删除根和右孩子),处理左孩子并返回
if t.val > high:
left = helper(t.left)
return left
# 3.如果结点的值位于区间 [low,high]
# 递归处理左,右子树
t.left = helper(t.left)
t.right = helper(t.right)
return t
return helper(root)
108.将有序数组转换为二叉搜索树
给你一个整数数组 nums
,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
数组构造二叉树,构成平衡树是自然而然的事情,因为大家默认都是从数组中间位置取值作为节点元素,一般不会随机取。所以想构成不平衡的二叉树是自找麻烦。
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
def helper(left, right):
if left > right:
return None
mid = left + (right-left)//2
root = TreeNode(nums[mid])
root.left = helper(left,mid-1)
root.right = helper(mid+1, right)
return root
return helper(0, len(nums)-1)
538.把二叉搜索树转换为累加树
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node
的新值等于原树中大于或等于 node.val
的值之和。
二叉搜索树满足左<根<右,所以为了知道比node值大的节点,需要按照 右,根,左的顺序访问(累加)。
class Solution:
def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
pre = 0 # 非局部变量pre,记录上一个(修改过的)节点的值
def traversal(cur):
nonlocal pre
if cur is None:
return
# 右
traversal(cur.right)
# 根
cur.val += pre
pre = cur.val
# 左
traversal(cur.left)
traversal(root)
return root