代码随想录算法训练营第二十天 | 二叉树part07
235 二叉搜索树的最近公共祖先
思路:这个题目的代码可以和236二叉树的最近公共祖先一模一样,但是由于其是二叉搜索树,所以可以使用其性质来简化代码
在有序树里,如果判断一个节点的左子树里有p,右子树里有q呢?
因为是有序树,所以 如果 中间节点是 q 和 p 的公共祖先,那么 中节点的数组 一定是在 [p, q]区间的。即 中节点 > p && 中节点 < q 或者 中节点 > q && 中节点 < p。
那么只要从上到下去遍历,遇到 cur节点是数值在[p, q]区间中则一定可以说明该节点cur就是p 和 q的公共祖先。 那问题来了,一定是最近公共祖先吗?
如图,我们从根节点搜索,第一次遇到 cur节点是数值在[q, p]区间中,即 节点5,此时可以说明 q 和 p 一定分别存在于 节点 5的左子树,和右子树中。
此时节点5是不是最近公共祖先? 如果 从节点5继续向左遍历,那么将错过成为p的祖先, 如果从节点5继续向右遍历则错过成为q的祖先。
所以当我们从上向下去递归遍历,第一次遇到 cur节点是数值在[q, p]区间中,那么cur就是 q和p的最近公共祖先。
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 二叉搜索树中的插入操作
思路:所有插入的节点都可以在叶子节点左右进行插入。所以使用递归的方法很简单。
if not root:
node = TreeNode(val)
return node
if root.val < val :
root.right = self.insertIntoBST(root.right,val)
else:
root.left = self.insertIntoBST(root.left,val)
return root
450 删除二叉搜索树中的节点
一般来说,删除节点可分为两个步骤:
- 首先找到需要删除的节点;
- 如果找到了,删除它。
删除的操作可以简化为,让其变成其右孩子,或者是变成其左孩子,道理是一样的。
五种情况:
- 没找到删除的点
- 删除的节点是叶子节点左为空右也为空
- 删除的节点左节点不为空右为空
- 删除的节点左节点为空右不为空
- 删除的节点左节点不为空右不为空
if not root:
return
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 not root.right and root.left:
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
简化代码:
if root is None: # 如果根节点为空,直接返回
return root
if root.val == key: # 找到要删除的节点
if root.right is None: # 如果右子树为空,直接返回左子树作为新的根节点
return root.left
cur = root.right
while cur.left: # 找到右子树中的最左节点
cur = cur.left
root.val, cur.val = cur.val, root.val # 将要删除的节点值与最左节点值交换
root.left = self.deleteNode(root.left, key) # 在左子树中递归删除目标节点
root.right = self.deleteNode(root.right, key) # 在右子树中递归删除目标节点
return root