235.二叉搜索树的最近公共祖先
思路
根据二叉搜索树的特性,使用中序遍历。
如果当前节点比p和q都大,则向左遍历;反之向右遍历;
如果当前节点在p和q之间,则返回该节点
情况二:最近公共祖先是p或q,返回当前节点
尝试写代码:
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if p.val < root.val and q.val < root.val:
return self.lowestCommonAncestor(root.left, p, q)
if p.val > root.val and q.val > root.val:
return self.lowestCommonAncestor(root.right, p, q)
if (p.val < root.val and q.val > root.val) or (p.val > root.val and q.val < root.val):
return root
elif p == root or q == root:
return root
成功通过!
根据代码随想录:
二叉搜索树本身就是有序的,不需要在判断用什么的遍历
向左向右遍历的情况之外,直接返回当前节点就行了
最终代码:
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if p.val < root.val and q.val < root.val:
return self.lowestCommonAncestor(root.left, p, q)
if p.val > root.val and q.val > root.val:
return self.lowestCommonAncestor(root.right, p, q)
return root
701.二叉搜索树中的插入操作
思路
如果值比节点大,向左遍历;反之向右遍历
尝试写代码:
class Solution:
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
if not root:
return TreeNode(val)
if not root.left and not root.right:
if val < root.val:
node = TreeNode(val)
root.left = node
if val > root.val:
node = TreeNode(val)
root.right = node
if val < root.val:
if root.left:
self.insertIntoBST(root.left, val)
else:
node = TreeNode(val)
root.left = node
return root
if val > root.val:
if root.right:
self.insertIntoBST(root.right, val)
else:
node = TreeNode(val)
root.right = node
return root
return root
成功通过
根据代码随想录
要点:
- 插入的节点都可以在叶子节点上找到位置
- 确定返回值,为新的二叉搜索树的根节点
- 终止条件:节点为空时,创立新节点,并返回该节点
- 给定值小于节点值,递归函数,返回值用root.left接住;大于同理
最终代码
class Solution:
def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
if not root:
node = TreeNode(val)
return node
if val < root.val:
root.left = self.insertIntoBST(root.left, val)
if val > root.val:
root.right = self.insertIntoBST(root.right, val)
return root
总结
直接考虑碰到叶子节点,即当前节点为空时就插入新节点,在后面递归时,再判断,将其分配给左节点还是右节点。
我一开始在终止条件就判断,应给分配给左节点还是右节点,这种思路会有很多可能性,就需要写很多个条件判断去处理,非常麻烦。
450.删除二叉搜索树中的节点
思路
终止条件判断:
如果节点值等于key
如果当前节点既有左孩子也有右孩子,则将右节点提上来
如果只有左孩子,则返回左孩子;右孩子同理
都没有,则返回None
下面递归的时候,用root.left或者root.right 接住。
尝试写代码:
class Solution:
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
if not root:
return None
if root.val == key:
if root.left and root.right:
root.right.left = root.left
return root.right
elif not root.left and root.right:
return root.right
elif root.left and not root.right:
return root.left
else:
return None
if key < root.val:
root.left = self.deleteNode(root.left, key)
if key > root.val:
root.right = self.deleteNode(root.right, key)
return root
测试用例通过,但结果不对
因为如果当前值的右孩子下面都是满的,则错误。
不知道该如何分离节点
根据代码随想录
要点:
- 分析有哪几种情况
- 没有找到要删除的节点
- 删除的是叶子节点,即 左空,右空
- 要删除的节点,左不空,右空
- 要删除的节点,左空,右不空
- 左不空,右不空
- 第五种情况最复杂,让右子树继位,然后将左子树放在右子树最小的节点,也就是最左侧的节点。
最终代码:
class Solution:
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
if not root:
return None
if root.val == key:
if not root.left and not root.right:
return None
elif not root.left and root.right:
return root.right
elif root.left and not root.right:
return root.left
else:
cur = root.right
while cur.left:
cur = cur.left
cur.left = root.left
return root.right
if key < root.val:
root.left = self.deleteNode(root.left, key)
if key > root.val:
root.right = self.deleteNode(root.right, key)
return root
总结:
整体思想差不多对,除了没想到第五种情况的复杂程度。这时,需要画出一个例子,观察思考。