235. 二叉搜索树的最近公共祖先(medium)
-
由于二叉搜索树只是二叉树的一个特例,那么236. 二叉树的最近公共祖先的题解是可以解决本题的。
-
然而,可以利用二叉搜索树的特性来解决。也就是比较root的值和 p和q的值来确定继续搜索左子树还是右子树。
-
递归法:
# 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):#step1
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
#step2
if root is None:
return None
#step3
if root.val > p.val and root.val > q.val:
left = self.lowestCommonAncestor(root.left, p, q)
if left:
return left
if root.val < p.val and root.val < q.val:
right = self.lowestCommonAncestor(root.right, p, q)
if right:
return right
return root
-
迭代法:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
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
701.二叉搜索树中的插入操作(medium)
-
trick: 在叶子结点插入
终止条件不是很直观。if root is None: #说明找到了正确的插入位置,那么就需要将这个Treenode返回(返回给上一层的左或右子树),而这个逻辑是需要在#step3单层递归逻辑中给出的。
-
递归法1:Carl
# 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 insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:#step1
#step2
if root is None:#找到了要插入的位置
node = TreeNode(val)
return node #返回给上一层的左子树或右子树(这个逻辑就在#step3中给出)
#step3
if root.val > val:
root.left = self.insertIntoBST(root.left, val) #简单来说就是在左子树插入一个node后需要更新左子树
if root.val < val:
root.right = self.insertIntoBST(root.right, val)
return root
-
递归法2: 题解
# 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):#step1
"""
:type root: TreeNode
:type val: int
:rtype: TreeNode
"""
node = TreeNode(val)
#step2
if root is None:
return node
#step3
if val < root.val:
self.insertIntoBST(root.left, val)
if val > root.val:
self.insertIntoBST(root.right, val)
if root.left is None and val < root.val:
root.left = node
if root.right is None and val > root.val:
root.right = node
return root
- 递归法2的step3逻辑稍稍调换了位置,这样方便理解。
- 但跟之前递归法同样的疑问是: 当要对左/右子树递归的时候为何不需要判断 if root.left: (or if root.right)?因为当递归到左子树时,此时的root已经变成root.left,这样 if root.left is None 就激活了step2的终止条件。
-
迭代法:
# 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
"""
node = TreeNode(val)
if root is None:
return node
parent = None #初始化一个parent变量,来记录父结点
cur = root
while cur:
if val < cur.val:
parent = cur
cur = cur.left
# elif val > cur.val:
else: #It is guaranteed that the new value does not exist in the original BST.
parent = cur
cur = cur.right
if val < parent.val:
parent.left = node
# if val > parent.val:
else:
parent.right = node
return root
450.删除二叉搜索树中的节点
-
递归思路:
只要把待删除节点和叶子结点做一个替换就好啦。如果有左子树就用左子树的最大值节点(最右下)替换,如果没有左子树就用右子树的最小值节点替换(最左下)。然后再把替换后的叶子结点删除
# 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]:#step1
#step2
if root is None:
return None
#step3
if key < root.val:
root.left = self.deleteNode(root.left, key) #更新左子树
elif key > root.val:
root.right = self.deleteNode(root.right, key) #更新右子树
else:
if not root.left:
return root.right
if not root.right:
return root.left
else:
#找到右子树的最小值节点,替换root的值,然后再把替换后的叶子结点删除(也是一步递归)
node = root.right
while node.left:
node = node.left
root.val = node.val
root.right = self.deleteNode(root.right, root.val)
return root
总结:
-
二叉搜索树的特性要灵活利用。很多操作都很巧妙,理解思路最重要。
-
递归法对于二叉树来说应该是相对容易的,首先掌握递归法。