leetcode(17)二叉搜索树系列题目

700. 二叉搜索树中的搜索

为什么要有返回值:
因为搜索到目标节点就要立即return,
这样才是找到节点就返回(搜索某一条边),如果不加return,就是遍历整棵树了。

class Solution:
    def searchBST(self, root: TreeNode, val: int) -> TreeNode:
        if not root:
            return
        if val == root.val:
            return root
        elif val < root.val:
            return self.searchBST(root.left, val)
        else:
            return self.searchBST(root.right, val)

98. 验证二叉搜索树

中序遍历二叉搜索书可得到一个升序数组,借助pre = float('-inf')来比较前一个元素和当前元素

class Solution:
    pre = float('-inf')
    def isValidBST(self, root: Optional[TreeNode]) -> bool:        
        if not root:
            return True
        if not self.isValidBST(root.left):  # 左
            return False
        if self.pre >= root.val:  # 中
            return False
        else:
            self.pre = root.val
        return self.isValidBST(root.right)  # 右

530. 二叉搜索树的最小绝对差

783. 二叉搜索树节点最小距离 为同一题
注意:与 98. 验证二叉搜索树 的区别是本题需要遍历整棵树,所以不加return,即不用把左子树和右子树的最小绝对差立即赋值给res

class Solution:
    pre = float('-inf')  # 不是0
    res = float('inf')
    def minDiffInBST(self, root: Optional[TreeNode]) -> int:
        if not root:
            return 0
        self.minDiffInBST(root.left)  # 不用赋值给res
        self.res = min(self.res, abs(self.pre - root.val))
        self.pre = root.val
        self.minDiffInBST(root.right)
        return self.res

501. 二叉搜索树中的众数

注意:与 530. 二叉搜索树的最小绝对差 类似,需要遍历整棵树
[Python O(1)空间] 一个很常规的二叉树处理方法,遍历的时候维护一个pre变量记录当前节点的父节点(prev最好用全局变量)。
BST中序遍历是有序的,所以用cnt来记录当前数值出现的频率, maxcnt来记录当前众数出现的次数。每当cnt > maxcnt的时候清空一下res结果集就行了(当然,clear()函数的复杂度是O(n),所以此方法时间上不是最优),但由于res结果集是不算额外空间的,所以满足空间是O(1).

class Solution:
    res = []
    cnt = 1
    max_cnt = 0
    pre = float('-inf')
    def findMode(self, root: TreeNode) -> List[int]:
        if not root:
            return
        self.findMode(root.left)
        if self.pre == root.val:
            self.cnt += 1
        else:
            self.cnt = 1
        if self.cnt == self.max_cnt:
            self.res.append(root.val)
        if self.cnt > self.max_cnt:
            self.res.clear()
            self.max_cnt = self.cnt
            self.res.append(root.val)
        self.pre = root.val
        self.findMode(root.right)
        return self.res

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

总共三种情况:

  • 当前节点为空,则直接添加
  • 左边或者右边为空时直接添加
  • 左右均不空则递归
class Solution:
    def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
        if not root:
            return TreeNode(val)
        # 左边或者右边为空时直接添加
        if not root.left and val < root.val:
            root.left = TreeNode(val)
        if not root.right and val > root.val:
            root.right = TreeNode(val)
        # 左右均不空则递归
        if val < root.val:
            self.insertIntoBST(root.left, val)
        if val > root.val:
            self.insertIntoBST(root.right, val)
        
        return root

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

有以下五种情况:

  • 第一种情况:没找到删除的节点,遍历到空节点直接返回了
  • 找到删除的节点
    • 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
    • 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
    • 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
    • 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子5)放到删除节点的右子树的最左面节点的左孩子8上,返回删除节点右孩子9为新的根节点
class Solution:
    def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
        if not root:  
            return
        if root.val == key:
            if not root.left and not root.right:  # 删除节点是叶子节点
                return
            elif not root.left and root.right:   # 删除节点只有右儿子,左儿子代替原节点
                root = root.right
            elif not root.right and root.left:   # 删除节点只有左儿子,左儿子代替原节点
                root = root.left
            else: # 既有左儿子,又有右儿子,把左子树接在右子树的最左节点的左边,右儿子代替原节点
                cur = root.right
                while cur.left:  # 是cur.left
                    cur = cur.left
                cur.left = root.left
                root = root.right

        elif root.val < key:
            root.right = self.deleteNode(root.right, key)  # 不用return,而是用right接住
        elif root.val > key:
            root.left = self.deleteNode(root.left, key)
        return root

669. 修剪二叉搜索树

注意:本题需要返回值,因为是要遍历整棵树,做修改,其实不需要返回值也可以,我们也可以完成修剪(其实就是从二叉树中移除节点)的操作。

但是有返回值,更方便,可以通过递归函数的返回值来移除节点

class Solution:
    def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
        if not root:
            return
        if root.val < low:
            return self.trimBST(root.right, low, high)  #直接返回右边的
        elif root.val > high:
            return self.trimBST(root.left, low, high)   #直接返回左边的
        elif low <= root.val <= high:
            root.left = self.trimBST(root.left, low, high)
            root.right = self.trimBST(root.right, low, high)
            return root

108. 将有序数组转换为二叉搜索树

第3个自己写出来的递归树!
再写又不会了...
通过索引把数组分为左右两边,注意写终止条件

class Solution:
    def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
        n = len(nums)
        if not n:
            return
        root_idx = n // 2
        root = TreeNode(nums[root_idx])
        root.left = self.sortedArrayToBST(nums[:root_idx])
        root.right = self.sortedArrayToBST(nums[root_idx + 1:])
        return root

538. 把二叉搜索树转换为累加树

换一个角度来看,这就是一个有序数组[2, 5, 13],求从后到前的累加数组,也就是[20, 18, 13],从后向前,挨个累加即可。
从树中可以看出累加的顺序是右中左,所以反中序遍历这个二叉树,然后顺序累加就可以了。
要遍历整棵树,因此递归函数不需要返回值
1038. 从二叉搜索树到更大和树 是同一题

class Solution:
    def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        def traversal(root):
            if not root:
                return
            traversal(root.right)
            self.sum_ += root.val
            root.val = self.sum_
            traversal(root.left)
        self.sum_ = 0
        traversal(root)
        return root

posted @ 2022-05-18 10:44  YTT77  阅读(34)  评论(0编辑  收藏  举报