代码随想录算法训练营day22 | 235. 二叉搜索树的最近公共祖先,701.二叉搜索树中的插入操作,450.删除二叉搜索树中的节点

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

总结:

  • 二叉搜索树的特性要灵活利用。很多操作都很巧妙,理解思路最重要。

  • 递归法对于二叉树来说应该是相对容易的,首先掌握递归法。

你可能感兴趣的:(算法,数据结构,leetcode,python)