235. 二叉搜索树的最近公共祖先
因为二叉搜索树的特性,我们无需遍历整棵树:
- 如果p和q都小于当前节点的值,说明它们在左子树上。
- 如果p和q都大于当前节点的值,说明它们在右子树上。
- 如果当前节点的值在p和q之间,或者等于p或q,那么当前节点为最近公共祖先。
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
# 递归
if not root or root == p or root == q:
return root
if root.val > p.val and root.val > q.val:
return self.lowestCommonAncestor(root.left, p, q)
if root.val < p.val and root.val < q.val:
return self.lowestCommonAncestor(root.right, p, q)
else:
return root
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
# 迭代
while root:
if root.val > p.val and root.val > q.val:
root = root.left
elif root.val < p.val and root.val < q.val:
root = root.right
else:
return root
return None
701.二叉搜索树中的插入操作
思路:根据二叉搜索树的规则,只需要在叶子节点处插入,不存在“内部插入”的情况:
- 从根节点开始:比较要插入的新值与当前节点的值。
- 向左或向右移动:
- 如果新值小于当前节点的值,向左子树移动;
- 如果新值大于当前节点的值,向右子树移动。
- 找到插入位置:当遇到一个
None
的左子节点或右子节点时,这表明找到了新值应该插入的位置。
class Solution:
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
# 如果当前节点为空,说明找到了插入位置
if not root:
insert_node = TreeNode(val)
return insert_node
if val < root.val:
root.left = self.insertIntoBST(root.left, val)
else:
root.right = self.insertIntoBST(root.right, val)
return root
迭代法:
- 开始于根节点:使用一个指针(
current
)从根节点开始遍历树。- 寻找插入位置:比较要插入的新值与当前节点的值。
- 如果新值小于当前节点的值,向左移动;
- 如果新值大于当前节点的值,向右移动。
- 维护父节点指针:在遍历过程中,维护一个父节点指针(
parent
),以便知道在哪里插入新节点。- 插入新节点:当
current
为null
,说明找到了插入位置,根据parent
节点的值与要插入的值的比较结果,将新节点插入到parent
的左侧或右侧。
class Solution:
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
# 迭代法
if not root:
insert_node = TreeNode(val)
return insert_node
current = root
parent = None
while current:
parent = current
if val > current.val:
current = current.right
else:
current = current.left
if val > parent.val:
parent.right = TreeNode(val)
else:
parent.left = TreeNode(val)
return root
450.删除二叉搜索树中的节点
在BST中删除节点
key
,大体上有以下几种情况:
- 节点不存在:如果树中没有节点的值等于
key
,则不需要删除,直接返回原树。- 节点是叶子节点:如果要删除的节点没有子节点,可以直接删除该节点。
- 节点只有一个子节点:如果要删除的节点只有一个左子节点或右子节点,可以让这个子节点直接替换要删除的节点。
- 节点有两个子节点:如果要删除的节点既有左子节点又有右子节点,一种常用的方法是用其右子树的最小节点(或左子树的最大节点)来替换这个节点,然后删除右子树的最小节点(或左子树的最大节点)。
# 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 deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
if not root:
return None
# 如果key小于当前节点,递归到左子树
if key < root.val:
root.left = self.deleteNode(root.left, key)
# 如果key大于当前节点,递归到右子树
elif key > root.val:
root.right = self.deleteNode(root.right, key)
# 如果key等于当前节点,找到了要删除的节点
else:
# 如果要删除的节点是叶子节点,则直接删除,返回None
# 如果要删除的节点有一个子节点,则用子节点替代,返回子节点
if not root.left:
return root.right
elif not root.right:
return root.left
# 如果要删除的节点有两个子节点,
# 找到右子树的最小节点(依然比当前节点大,因为是搜索树)
# 替换当前节点,并删除右子树最小节点
else:
minNode = self.findMin(root.right)
root.val = minNode.val
root.right = self.deleteNode(root.right, minNode.val)
return root
def findMin(self, node):
while node.left:
node = node.left
return node
可以看到,向搜索树添加元素很简单,因为不需要改变树的结构,而删除节点则需要改变结构。