leetcode(17)二叉搜索树系列题目
700. 二叉搜索树中的搜索
为什么要有返回值:
因为搜索到目标节点就要立即return,
这样才是找到节点就返回(搜索某一条边),如果不加return,就是遍历整棵树了。
class Solution:
def searchBST(self, root: TreeNode, val: int) -> TreeNode:
if not root:
return
if val == root.val:
return root
elif val < root.val:
return self.searchBST(root.left, val)
else:
return self.searchBST(root.right, val)
98. 验证二叉搜索树
中序遍历二叉搜索书可得到一个升序数组,借助pre = float('-inf')来比较前一个元素和当前元素
class Solution:
pre = float('-inf')
def isValidBST(self, root: Optional[TreeNode]) -> bool:
if not root:
return True
if not self.isValidBST(root.left): # 左
return False
if self.pre >= root.val: # 中
return False
else:
self.pre = root.val
return self.isValidBST(root.right) # 右
530. 二叉搜索树的最小绝对差
与 783. 二叉搜索树节点最小距离 为同一题
注意:与 98. 验证二叉搜索树 的区别是本题需要遍历整棵树,所以不加return,即不用把左子树和右子树的最小绝对差立即赋值给res
class Solution:
pre = float('-inf') # 不是0
res = float('inf')
def minDiffInBST(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
self.minDiffInBST(root.left) # 不用赋值给res
self.res = min(self.res, abs(self.pre - root.val))
self.pre = root.val
self.minDiffInBST(root.right)
return self.res
501. 二叉搜索树中的众数
注意:与 530. 二叉搜索树的最小绝对差 类似,需要遍历整棵树
[Python O(1)空间] 一个很常规的二叉树处理方法,遍历的时候维护一个pre变量记录当前节点的父节点(prev最好用全局变量)。
BST中序遍历是有序的,所以用cnt来记录当前数值出现的频率, maxcnt来记录当前众数出现的次数。每当cnt > maxcnt的时候清空一下res结果集就行了(当然,clear()函数的复杂度是O(n),所以此方法时间上不是最优),但由于res结果集是不算额外空间的,所以满足空间是O(1).
class Solution:
res = []
cnt = 1
max_cnt = 0
pre = float('-inf')
def findMode(self, root: TreeNode) -> List[int]:
if not root:
return
self.findMode(root.left)
if self.pre == root.val:
self.cnt += 1
else:
self.cnt = 1
if self.cnt == self.max_cnt:
self.res.append(root.val)
if self.cnt > self.max_cnt:
self.res.clear()
self.max_cnt = self.cnt
self.res.append(root.val)
self.pre = root.val
self.findMode(root.right)
return self.res
701. 二叉搜索树中的插入操作
总共三种情况:
- 当前节点为空,则直接添加
- 左边或者右边为空时直接添加
- 左右均不空则递归
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
450. 删除二叉搜索树中的节点
有以下五种情况:
- 第一种情况:没找到删除的节点,遍历到空节点直接返回了
- 找到删除的节点
- 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
- 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
- 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
- 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子5)放到删除节点的右子树的最左面节点的左孩子8上,返回删除节点右孩子9为新的根节点。
class Solution:
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
if not root:
return
if root.val == key:
if not root.left and not root.right: # 删除节点是叶子节点
return
elif not root.left and root.right: # 删除节点只有右儿子,左儿子代替原节点
root = root.right
elif not root.right and root.left: # 删除节点只有左儿子,左儿子代替原节点
root = root.left
else: # 既有左儿子,又有右儿子,把左子树接在右子树的最左节点的左边,右儿子代替原节点
cur = root.right
while cur.left: # 是cur.left
cur = cur.left
cur.left = root.left
root = root.right
elif root.val < key:
root.right = self.deleteNode(root.right, key) # 不用return,而是用right接住
elif root.val > key:
root.left = self.deleteNode(root.left, key)
return root
669. 修剪二叉搜索树
注意:本题需要返回值,因为是要遍历整棵树,做修改,其实不需要返回值也可以,我们也可以完成修剪(其实就是从二叉树中移除节点)的操作。
但是有返回值,更方便,可以通过递归函数的返回值来移除节点。
class Solution:
def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
if not root:
return
if root.val < low:
return self.trimBST(root.right, low, high) #直接返回右边的
elif root.val > high:
return self.trimBST(root.left, low, high) #直接返回左边的
elif low <= root.val <= high:
root.left = self.trimBST(root.left, low, high)
root.right = self.trimBST(root.right, low, high)
return root
108. 将有序数组转换为二叉搜索树
第3个自己写出来的递归树!
再写又不会了...
通过索引把数组分为左右两边,注意写终止条件
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
n = len(nums)
if not n:
return
root_idx = n // 2
root = TreeNode(nums[root_idx])
root.left = self.sortedArrayToBST(nums[:root_idx])
root.right = self.sortedArrayToBST(nums[root_idx + 1:])
return root
538. 把二叉搜索树转换为累加树
换一个角度来看,这就是一个有序数组[2, 5, 13],求从后到前的累加数组,也就是[20, 18, 13],从后向前,挨个累加即可。
从树中可以看出累加的顺序是右中左,所以反中序遍历这个二叉树,然后顺序累加就可以了。
要遍历整棵树,因此递归函数不需要返回值。
与 1038. 从二叉搜索树到更大和树 是同一题
class Solution:
def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
def traversal(root):
if not root:
return
traversal(root.right)
self.sum_ += root.val
root.val = self.sum_
traversal(root.left)
self.sum_ = 0
traversal(root)
return root