题目:
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
- 首先找到需要删除的节点;
- 如果找到了,删除它。
思路:
分为5种情况:
1.没找到待删除的结点,直接返回根节点;
找到待删除的结点:
2.待删除结点(叶子结点)左右孩子皆为空,返回None;
3.待删除结点左空右不空,返回右孩子结点;
4.待删除结点右空左不空,返回左孩子结点;
5.待删除结点左右孩子都不空(难点所在),解决方法下面详述。
解答:
方法一:递归
(1)借助二叉搜索树的特性:
当待删除结点的左右孩子都不空时,找到待删除结点的后序结点,然后将待删除结点的左孩子 置为 其后序结点的左孩子,再返回待删除结点的右孩子结点。
# 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 root
if root.val==key:
#左右都空
if (not root.left) and (not root.right):
return None
#左空右不空
elif not root.left:
return root.right
#左不空有空
elif not root.right:
return root.left
#左右都不空
else:
cur=root.right
while cur.left:
cur=cur.left
cur.left=root.left
root=root.right
return root
elif root.val<key:
root.right=self.deleteNode(root.right,key)
else:
root.left=self.deleteNode(root.left,key)
return root
示例效果图:
(2)当待删除结点的左右孩子都不空时,找到待删除结点的前序结点,然后将待删除结点的右孩子 置为 其前序结点的右孩子,再返回待删除结点的左孩子结点。
# 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 root
if root.val==key:
#左右都空
if (not root.left) and (not root.right):
return None
#左空右不空
elif not root.left:
return root.right
#左不空有空
elif not root.right:
return root.left
#左右都不空
else:
cur=root.left
while cur.right:
cur=cur.right
cur.right=root.right
root=root.left
return root
elif root.val<key:
root.right=self.deleteNode(root.right,key)
else:
root.left=self.deleteNode(root.left,key)
return root
示例效果图:
(3)没有完全借助二叉搜索树的特性:
当待删除结点的左右孩子都不空时,找到待删除结点的后序结点,然后将待删除结点的值 与 其后序结点的值进行交换,再进行删除。
# 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 root
if root.val==key:
#如果右空,起最终删除的作用
if not root.right:
return root.left
#找到待删除结点的后序结点,并交换结点值
cur=root.right
while cur.left:
cur=cur.left
tmp=cur.val
cur.val=root.val
root.val=tmp
root.left=self.deleteNode(root.left,key)
root.right=self.deleteNode(root.right,key)
return root
示例效果图:
(4)没有完全借助二叉搜索树的特性:
当待删除结点的左右孩子都不空时,找到待删除结点的前序结点,然后将待删除结点的值 与 其前序结点的值进行交换,再进行删除。
# 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 root
if root.val==key:
#如果左空,起最终删除的作用
if not root.left:
return root.right
#找到待删除结点的前序结点,并交换结点值
cur=root.left
while cur.right:
cur=cur.right
tmp=cur.val
cur.val=root.val
root.val=tmp
root.left=self.deleteNode(root.left,key)
root.right=self.deleteNode(root.right,key)
return root
示例效果图:
方法二:迭代
- 方法一(1)的转化
# 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 deleteOneNode(self,target):
#找后序节点
if not target:
return target
if not target.right:
return target.left
cur=target.right
while cur.left:
cur=cur.left
cur.left=target.left
return target.right
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
#将待删除结点值与后序节点值交换,之后再删除
if not root:
return root
parent=None #记录cur的父节点,用来删除cur
cur=root
while cur: #寻找待删除结点
if cur.val==key:
break
parent=cur
if cur.val>key:
cur=cur.left
else:
cur=cur.right
if not cur: #未找到待删除结点
return root
if not parent: #待删除结点为树的根节点
return self.deleteOneNode(cur)
else:
#判断要删除的是parent的左孩子还是右孩子
if parent.left and cur.val==parent.left.val:
parent.left=self.deleteOneNode(cur)
if parent.right and cur.val==parent.right.val:
parent.right=self.deleteOneNode(cur)
return root
- 方法一(2)的转化:
# 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 deleteOneNode(self,target):
#找前序结点
if not target:
return target
if not target.left:
return target.right
cur=target.left
while cur.right:
cur=cur.right
cur.right=target.right
return target.left
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
#将待删除结点值与后序节点值交换,之后再删除
if not root:
return root
parent=None #记录cur的父节点,用来删除cur
cur=root
while cur: #寻找待删除结点
if cur.val==key:
break
parent=cur
if cur.val>key:
cur=cur.left
else:
cur=cur.right
if not cur: #未找到待删除结点
return root
if not parent: #待删除结点为树的根节点
return self.deleteOneNode(cur)
else:
#判断左右
if parent.left and cur.val==parent.left.val:
parent.left=self.deleteOneNode(cur)
if parent.right and cur.val==parent.right.val:
parent.right=self.deleteOneNode(cur)
return root