235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)
由于是二叉搜索树,当节点值在p、q之间时,节点就是最近公共祖先,因为此时p、q分别在节点左右子树上;当节点值小于p、q,则往右子树搜索;当节点值大于p、q,则往左子树搜索。
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root:
return None
if root == q or root == p:
return root
if root.val < p.val and root.val < q.val:
return self.lowestCommonAncestor(root.right, p, q)
elif root.val > p.val and root.val > q.val:
return self.lowestCommonAncestor(root.left, p, q)
else:
return root
701. 二叉搜索树中的插入操作 - 力扣(LeetCode)
首先排除测试样例的root为空;
比较当前节点值与插入值,向下访问左、右孩子。若待插入位置为空,直接添加节点即可;若不为空,递归调用函数,传入子树根节点和插入值。
* 所以这里不需要root.left = self.insertIntoBST(root.left, val),而是直接调用:self.insertIntoBST(root.left, val)。
class Solution:
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
if not root:
return TreeNode(val = val)
if root.val < val:
if not root.right:
root.right = TreeNode(val = val)
else:
self.insertIntoBST(root.right, val)
else:
if not root.left:
root.left = TreeNode(val = val)
else:
self.insertIntoBST(root.left, val)
return root
450. 删除二叉搜索树中的节点 - 力扣(LeetCode)
解法一:用两个递归函数,一个找待删除节点,另一个返回删除后的子树。用待删除节点的左子树的最右侧节点替换待删除节点。
self.deleteNode():若目标小于当前值,到左子树找目标,并将左子树修改为删除后的子树,否则对右子树操作。若目标==当前值,找到待删除节点,设置全局变量,将待删除节点的左子树传入self.func()。
func()需要找到这个左子树最右侧的节点node,将node替换待删除节点就可以保持二叉搜索树的特性(也可以传入右子树,找最左侧节点,替换待删除节点)。全局变量self.pre保存左子树当前访问节点的父节点,self.isfirst指示是否首次调用self.func(),self.left和self.right分别是待删除节点原来的左右孩子。之所以用self.isfirst分两种情况处理,是因为self.isfirst==True时,node是其父节点的左子,否则是其右子。
若待删除节点左孩子为空,直接将它的右子树向上移动替换掉待删除节点即可,即返回它的右孩子。
若首次调用self.func()就访问到没有右孩子的节点node,就将以node为根的子树整体向上移动,node替换掉删除的节点,self.right成为node的右孩子,返回node。
否则,将self.isfirst设为False,更新self.pre,递归访问当前节点右孩子并返回。
若在self.isfirst==False时遇到没有右孩子的节点node,1)先将node删掉:将node的左孩子赋给self.pre.right;2)将node移动到原本待删除节点的位置将其替换:将self.left和self.right赋给node.left和node.right,返回node。
class Solution:
def func(self, root):
if not root:
return self.pre.right
if not root.right:
if self.isfirst:
root.right = self.right
return root
else:
self.pre.right = root.left
root.left = self.left
root.right = self.right
return root
self.isfirst = False
self.pre = root
return self.func(root.right)
def deleteNode(self, root, key: int):
if not root:
return None
if root.val == key:
self.pre = root
self.left = root.left
self.right = root.right
self.isfirst = True
return self.func(root.left)
if root.val > key:
root.left = self.deleteNode(root.left, key)
else:
root.right = self.deleteNode(root.right, key)
return root
解法二:将待删除节点的左子树移动到待删除节点右子树的最左侧节点的左孩子位置。
更简洁直观,不容易出错。
class Solution:
def deleteNode(self, root, key: int):
if not root:
return None
if root.val == key:
if not root.left:
return root.right
if not root.right:
return root.left
if root.left and root.right:
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)
else:
root.right = self.deleteNode(root.right, key)
return root