Day20 第六章 二叉树Part7 二叉搜索树的增删查

任务

235. 二叉搜索树的最近公共祖先

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

思路

由于是二叉搜索树,所以可以利用其性质一路向下进行查找,即,只有在p和q的值的范围内的才是其祖先,当第一次遇到符合条件节点的时候,就是其最近公共祖先,再一路向上返回。
如果不满足条件时,递归的向其子树一路向下的寻找。

  • 局部: 是否满足节点的数值条件
  • 子树递归: 根据值的大小和BST的性质向下(左或右)寻找
  • 返回值: 向上层返回当前的信息,告诉上层我找到了,节点是XXX。
class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        return self.dfs(root,p,q)
    
    def dfs(self,node,p,q):
        if not node: return None
        if node.val > p.val and node.val > q.val:
            return self.dfs(node.left,p,q)
        elif node.val < p.val and node.val < q.val:
            return self.dfs(node.right,p,q)
        else: return node

701. 二叉搜索树中的插入操作

思路

插入的初步也是找到插入的位置,即查找。根据对BST的分析,任意数值都可以插入成为叶子节点以满足题意,这样的作法最简单,不需要调整树的结构。
个人觉得无返回值的逻辑比较好理解,就是处理上只有递没有归的过程,一直告诉下层你去合适的位置插入节点,直到到达目标位置,之后归的过程全是空,即无返回值,因为到达叶子节点做完插入这件事后,归的过程父节点不需要子节点的信息了(虽然这个过程是一定会进行的)

  • 边界条件:如果是空树,直接构造并返回新的节点。
  • 边界条件:到达插入位置的父节点后,将新节点插入
  • 子树递归: 根据BST性质,向左或者向右遍历,直到到达插入位置的父节点
class Solution:
    def __init__(self):
        self.pre = None
    def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
        if not root:
            return TreeNode(val)
        self.dfs(root,val)
        return root
    def dfs(self,node,value):
        if not node:
            newNode = TreeNode(value)
            if self.pre.val > value:
                self.pre.left = newNode
            else:
                self.pre.right = newNode
        
        else:
            self.pre = node
            if value < node.val:
                self.dfs(node.left,value)
            elif value > node.val:
                self.dfs(node.right,value)
        

而代码随想录的有返回值的思路有点不好理解,细细分析后也比较方便,且写法上比较简洁,这里给出思路分析和代码

  • 如果是空树,或者说找到插入位置,直接构造并返回新的节点。
  • 子树递归:根据值的大小向左右层递归,并修改当前层的左或右指针(实际只有到达最后一层之前才实际接上了新节点,而其他节点的操作和覆盖相同(比如node.left = 下一层左边返回的node,但是这个语句进行后和不进行是一样的,等于啥都没做,只是递归的归的过程自然进行,之所以还需要也是为了接新节点的那次链接)
  • 返回值: 返回自身节点,是为了子树归的过程中,赋值给上层的left或者right
class Solution:
    def insertIntoBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
        return self.dfs(root,val)
        
    def dfs(self,node,value):
        if not node:
            newNode = TreeNode(value)
            return newNode
        
        if value < node.val:
            node.left =  self.dfs(node.left,value)
            return node
        elif value > node.val:
            node.right = self.dfs(node.right,value)
            return node

450. 删除二叉搜索树中的节点

思路

逻辑是找到并删除。

  • 找的过程用递归中递的逻辑,且需要接底层返回的节点,归的时候是向上返回删除后的当前节点。
  • base case比较复杂,分为5种情况,代码中有详细注释
class Solution:
    def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
        return self.dfs(root,key)
        
    def dfs(self,node,value):
        if not node: return None # 情况1,没找到
        if node.val == value:
            if not node.left and not node.right:  #情况2,删除节点为叶子节点
                return None
            if not node.left and node.right:  #情况3,删除节点没有左孩子
                return node.right
            if node.left and not node.right:  #情况4,删除节点没有右孩子
                return node.left
            else: #情况5,删除的节点有左右孩子,则将其左子树放到右子树最左,然后用右孩子替代删除节点
                cur = node.right
                while cur.left:
                    cur = cur.left
                cur.left = node.left
                return node.right

        if value < node.val: 
            node.left = self.dfs(node.left,value)
        else:
            node.right = self.dfs(node.right,value)    
        return node

心得体会

学习了BST的增删查,总体思路为由BST性质一路向下找到对应的节点,进行操作,然后返回上层合法的节点并用上层的指针域链接。

posted @ 2024-08-05 14:21  haohaoscnblogs  阅读(25)  评论(0)    收藏  举报