代码随想录算法训练营第22天|二叉树part08| 235. 二叉搜索树的最近公共祖先、 701.二叉搜索树中的插入操作、450.删除二叉搜索树中的节点
35. 二叉搜索树的最近公共祖先
自己做
思路:
二叉搜索树和普通的二叉树在处理最近公共祖先的问题上有什么不同?
利用二叉搜索树的特性:
-
如果根结点等于q或者q,那么直接返回根结点
-
如果q和p在跟根结点的两侧,那么也是直接返回根结点
-
如果q和p在根结点的同侧,那么进入到所在侧,进入所在侧以后,重复1,2,3步->有返回值的,返回单条路径的递归
代码:
python
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
# 二叉搜索树和普通的二叉树在处理最近公共祖先的问题上有什么不同?
#
'''
利用二叉搜索树的特性:
1. 如果根结点等于q或者q,那么直接返回根结点
2. 如果q和p在跟根结点的两侧,那么也是直接返回根结点
3. 如果q和p在根结点的同侧,那么进入到所在侧,进入所在侧以后,重复1,2,3步->有返回值的,返回单条路径的递归
'''
# 在根结点
#print(root.left.val, p.val, q.val)
if root.val == q.val or root.val == p.val:
#print(1)
return root
# 在两边
if (root.val > p.val and root.val < q.val) or (root.val > q.val and root.val < p.val):
#print(2)
return root
# 3. 单层递归逻辑
if root.val > p.val and root.val > q.val:
# 都在左侧
#print(3)
#print(root.left.val)
#print(root.left.val, p.val, q.val)
return self.lowestCommonAncestor(root.left, p, q)
elif root.val < p.val and root.val < q.val:
# 都在右侧
#print(5)
return self.lowestCommonAncestor(root.right, p, q)
#print(5)
代码随想录
思路:
只要从上到下去遍历,遇到 cur节点是数值在[p, q]区间中则一定可以说明该节点cur就是q 和 p的公共祖先。
代码:
python
class Solution:
def traversal(self, cur, p, q):
if cur is None:
return cur
# 中
if cur.val > p.val and cur.val > q.val: # 左
left = self.traversal(cur.left, p, q)
if left is not None:
return left
if cur.val < p.val and cur.val < q.val: # 右
right = self.traversal(cur.right, p, q)
if right is not None:
return right
return cur # 都不满足那就是在中间了!!!
def lowestCommonAncestor(self, root, p, q):
return self.traversal(root, p, q)
701.二叉搜索树中的插入操作
自己做
思路:
见代码,唯一需要注意的是需要在向下搜索的过程中需要有一个判断
代码:
python
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def insertIntoBST(self, root, val):
"""
:type root: TreeNode
:type val: int
:rtype: TreeNode
"""
if root == None:
root = TreeNode(val)
return root
if root.val < val:
if root.right != None:
self.insertIntoBST(root.right, val)
if root.right == None:
cur = TreeNode(val)
root.right = cur
if root.val > val:
if root.left != None:
self.insertIntoBST(root.left, val)
if root.left == None:
cur = TreeNode(val)
root.left = cur
return root
代码随想录
思路:
搜索树是有方向了,可以根据插入元素的数值,决定递归方向。
代码:
python
class Solution:
def insertIntoBST(self, root, val):
if root is None:
node = TreeNode(val)
return node
if root.val > val:
root.left = self.insertIntoBST(root.left, val)
if root.val < val:
root.right = self.insertIntoBST(root.right, val)
return root
到这里,大家应该能感受到,如何通过递归函数返回值完成了新加入节点的父子关系赋值操作了,下一层将加入节点返回,本层用root->left或者root->right将其接住。
450.删除二叉搜索树中的节点
思路:
难点在于:
找到了结点如何删除并保证删除之后的树还是二叉搜索树
我的思路
分情况讨论:
-
如果是叶子结点->直接删除
-
如果只有左子树->用左子树最右侧结点替换
-
如果只有右子树->用右子树最左面结点替换
-
如果既有左子树又有右子树->用左子树最右侧结点替换或用左子树最右侧结点替换
第四种情况的理解是错误的,有些情况处理不了
左子树最右侧结点和左子树最右侧结点 都不存在 这时替换会破坏整个树的结构
最终代码没有实现,下面的代码是自己按照答案自己写的
代码:
python
代码随想录
思路:
递归三部曲
-
确定递归函数参数以及返回值
def deleteNone(self, root, key)
-
确定终止条件:遇到空返回,其实这也说明没找到删除的节点,遍历到空节点直接返回了
if root == None: return root # 1.
-
确定单层递归的逻辑
有以下五种情况:
-
第一种情况:没找到删除的节点,遍历到空节点直接返回了
-
找到删除的节点
-
第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
-
第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
-
第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
-
第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
if root.val == key: # 2. if not root.left and not root.right: return None # 3. if not root.left and root.right: # 右孩子补位 return root.right # 4. if root.left and not root.right: # 左孩子补位 return root.left # 5. if root.left and root.right: cur = root.right while cur.left != None: cur = cur.left cur.left = root.left return root.right
if root.val < key: root.right = self.deleteNone(root.right, key) if root.val > key: root.left = self.deleteNone(root.left, key)
-
代码:
python
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def deleteNode(self, root, key):
"""
:type root: TreeNode
:type key: int
:rtype: TreeNode
"""
if root == None: return root # 1.
if root.val == key:
# 2.
if not root.left and not root.right:
return None
# 3.
if not root.left and root.right:
# 右孩子补位
return root.right
# 4.
if root.left and not root.right:
# 左孩子补位
return root.left
# 5.
if root.left and root.right:
cur = root.right
while cur.left != None:
cur = cur.left
cur.left = root.left
return root.right
if root.val < key:
root.right = self.deleteNode(root.right, key)
if root.val > key:
root.left = self.deleteNode(root.left, key)
return root