Leetcode面试经典150题刷题记录 —— 二叉搜索树篇

这篇具有很好参考价值的文章主要介绍了Leetcode面试经典150题刷题记录 —— 二叉搜索树篇。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Leetcod面试经典150题刷题记录-系列
Leetcod面试经典150题刷题记录——数组 / 字符串篇
Leetcod面试经典150题刷题记录 —— 双指针篇
Leetcod面试经典150题刷题记录 —— 矩阵篇
Leetcod面试经典150题刷题记录 —— 滑动窗口篇
Leetcod面试经典150题刷题记录 —— 哈希表篇
Leetcod面试经典150题刷题记录 —— 区间篇
Leetcod面试经典150题刷题记录——栈篇
Leetcod面试经典150题刷题记录——链表篇
Leetcod面试经典150题刷题记录——二叉树篇
Leetcod面试经典150题刷题记录——二叉树层次遍历篇
本篇:Leetcod面试经典150题刷题记录——二叉搜索树篇

遇到二叉搜索树(BST)的题目,一旦用了sort()直接挂掉面试,切记!

二叉搜索树性质

二叉搜索树的性质满足:
(1)左节点 > root > 右节点 (局部性质)
(2)左子树所有节点 > root > 右子树所有节点 (全局性质,该性质包括局部性质,所以更重要)
相当部分程序员写起上面的局部性质很容易,写全局性质的判断就容易犯病,不瞒你说,我也是。

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

题目链接:二叉搜索树的最小绝对差 - leetcode
题目描述:
给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。差值是一个正数,其数值等于两值之差的绝对值。
题目归纳:

解题思路:
解法: 验证二叉搜索树 - leetcode官方题解

脏乱差版本

# 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

# 返回二叉搜索树中,任意两个不同节点值之间的最小差值
# 性质
# (1)二叉搜索树。题目既然说了,那么肯定要用到该性质
# (2)任意两个不同节点值,强调了任意两个不同节点。但是既然是二叉搜索树了,拿右子树中的节点 - 左子树中的节点肯定不会是答案,所以这里的任意其实是带引号的"任意",不是绝对的"任意",是可以忽略一些情况的"任意"

# 以root节点为例,要查找的目标点一定是下面两种情况
# (1)左树的最右节点 = 左树的最大节点 = 中序遍历的前驱pre节点
# (2)右树的最左节点 = 右树的最大节点 = 中序遍历的后继post节点
# 最后递归搜索
class Solution:
    def getMinDistance(self, root: Optional[TreeNode]) -> int:
        if not root: return 0
        
        # (1)查找左树的最'右'节点 = 左树的最大节点
        LR = root.left
        while LR and (LR.left or LR.right):
            # 有右边找右边,没右边找左边再找右边
            if LR.right:
                LR = LR.right
            else:
                break
        
        # (2)查找右树的最'左'节点 = 右树的最大节点
        RL = root.right
        while RL and (RL.left or RL.right):
            if RL.left:
                RL = RL.left
            else:
                break

        left_result = 1e9
        if LR:            left_result = abs(root.val-LR.val)
        right_result = 1e9
        if RL:            right_result = abs(root.val-RL.val)
        return min(left_result, right_result)

    def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
        result = 1e9

        # 逐个遍历
        queue = deque([root])
        while queue:
            size = len(queue)
            for i in range(size):
                node = queue.popleft() 
                if node.left: queue.append(node.left)
                if node.right: queue.append(node.right)
                
                dis = self.getMinDistance(node)
                result = min(result, dis)
        return result

优雅版本

# 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 __init__(self):
        self.result = float('inf')
        self.pre = None

    def traversal(self, cur):
        if cur is None:
            return None
        
        self.traversal(cur.left)  # 左
        
        if self.pre:  # 中
            self.result = min(self.result, cur.val - self.pre.val)
        self.pre = cur  # 记录前一个
        
        self.traversal(cur.right)  # 右

    def getMinimumDifference(self, root):
        self.traversal(root)
        return self.result

2. 二叉搜索树中第K小的元素

题目链接:二叉搜索树中第K小的元素 - leetcode
题目描述:
给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。
题目归纳:
中序遍历BST成有序数组,然后再找到这个有序数组的第k个元素?NoNoNo。掌握递归转换成迭代的关键思想,即将"函数调用栈"明写在代码里。

解题思路:
解法: 二叉搜索树中第K小的元素 - leetcode官方题解
中序遍历的迭代写法,注意,非递归!

# 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

# 这道题掌握两个知识点
# (1)中序遍历的迭代写法。即将函数调用栈明示出来,因为函数调用栈也是个栈,所有的递归写法都是可以转换为迭代版写法的,手动模拟函数调用栈即可。
# (2)二叉搜索树的中序遍历是有序的。

class Solution:
    def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
        # 中序遍历,迭代版而非递归
        stack = []
        while root or stack:
            # 相当于递归版写法的左子树遍历
            while root: # 压栈方向是单一的,沿着二叉树的右上角->左下角方向压栈
                stack.append(root)
                root = root.left
            root = stack.pop() # 遇到空就出栈
            # if root: print(root.val)
            k -= 1
            if k == 0:
                return root.val
            root = root.right

3. 验证二叉搜索树

题目链接:验证二叉搜索树 - leetcode
题目描述:
给定一个二叉树的 根节点 root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
题目归纳:
右视图 = 右边的侧视图

解题思路:
解法: 验证二叉搜索树 - leetcode官方题解
(1) 从左到右层序遍历。记录层序遍历的最后一个node,即为右视图看到的第一个node。

经典错误(从局部性质推断全局性质)

# 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 isValidBST(self, root: Optional[TreeNode]) -> bool:
        # 这是一道21年的408考研真题,空节点和叶节点都是二叉搜索树
        # 注意下面的写法是错误的,原因在于只判断了局部的性质,而忽略了全局的性质
        if not root: return True
        if not root.left and not root.right: return True
        
        # (1)这个时候root肯定存在,左树或许存在,结合root与左树根节点,判断是不是二叉搜索树
        if root and root.left and root.left.val < root.val:
            return self.isValidBST(root.left)
        else:
            return False

        # (2)这个时候root肯定存在,右树或许存在,结合root与右树根节点,判断是不是二叉搜索树
        if root and root.right and root.val < root.right.val:
            return self.isValidBST(root.right)
        else:
            return False

利用第1题的代码(有pre指针的那段)

# 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 __init__(self):
        self.pre = None

    def isValidBST(self, root: Optional[TreeNode]) -> bool:
        if not root:
            return True
        left = self.isValidBST(root.left)
        
        if self.pre and self.pre.val >= root.val: # __比第1题加了这个判断__
            return False
        self.pre = root # 要遍历root.right了,这个时候记录pre节点
        
        right = self.isValidBST(root.right)
        
        return left and right # 两边都要是BST树

附加题

1. 不同的二叉搜索树

题目链接:不同的二叉搜索树 - leetcode
题目描述:
给你一个整数 n ,求恰由 n 个节点组成且节点值从 1n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
题目归纳:
分治+动态规划

解题思路:
解法: 不同的二叉搜索树 - leetcode官方题解文章来源地址https://www.toymoban.com/news/detail-819389.html

class Solution:
    def numTrees(self, n: int) -> int:
        # 给一个整数n,求恰好由n个节点组成,且节点值从1到n,能够组成多少种不同的二叉搜索树。
        #给定一个有序序列1...n,遍历数字i,将数字i作为root,1 ... (i-1)序列作为左子树,(i+1) ... n作为右子树,接着按照同样的方式递归构建左子树和右子树
        # 在上述构建过程中,由于根root值不同,因此能保证每棵BST是唯一的。
        
        # 采用动态规划来求解本题
        # G(n): 长度为n的序列,所能构成的不同的BST树的个数。注意到 G(n) 和序列的内容无关,只和序列的长度有关
        # F(i,n):以i为根、序列长度为n的不同BST的个数
        # G(n) = sum_{1}^{n}F(i,n)
        # 特别的: G(0) = 1 , G(1) = 1
        # F(i,n) = G(i-1)*G(n-i)
        # ==> G(n) = sum_{1}^{n}G(i-1)G(n-i)
        G = [0] * (n+1)
        G[0] = 1
        G[1] = 1
        for i in range(2, n+1):
            for j in range(1, i+1):
                G[i] += G[j-1] * G[i-j]
        return G[n]

到了这里,关于Leetcode面试经典150题刷题记录 —— 二叉搜索树篇的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【leetcode刷题之路】面试经典150题(8)——位运算+数学+一维动态规划+多维动态规划

    20 位运算 20.1 【位运算】二进制求和 题目地址:https://leetcode.cn/problems/add-binary/description/?envType=study-plan-v2envId=top-interview-150   按位逆序运算。 20.2 【位运算】颠倒二进制位 题目地址:https://leetcode.cn/problems/reverse-bits/description/?envType=study-plan-v2envId=top-interview-150   详见代码

    2024年04月16日
    浏览(25)
  • 【LeetCode-经典面试150题-day12】

    20.有效的括号 题意: 给定一个只包括  \\\'(\\\' , \\\')\\\' , \\\'{\\\' , \\\'}\\\' , \\\'[\\\' , \\\']\\\'  的字符串  s  ,判断字符串是否有效。 有效字符串需满足: 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 每个右括号都有一个对应的相同类型的左括号。 【输入样例】s=\\\"

    2024年02月11日
    浏览(9)
  • 【LeetCode-面试经典150题-day14】

    【LeetCode-面试经典150题-day14】

      目录 19.删除链表的倒数第N个结点  82.删除排序链表中的重复元素Ⅱ  61. 旋转链表  86.分隔链表  146.LRU缓存 19.删除链表的倒数第N个结点 题意: 给你一个链表,删除链表的倒数第  n   个结点,并且返回链表的头结点。 【输入样例】head = [1,2,3,4,5],n=2 【输出样例】[1,2,3,5

    2024年02月11日
    浏览(8)
  • 【LeetCode-经典面试150题-day11】

    目录 128.最长连续序列  228.汇总区间  56.合并区间  57.插入区间  452.用最少数量的箭引爆气球   128.最长连续序列 题意: 给定一个未排序的整数数组  nums  ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 请你设计并实现时间复杂度为  O(n)   的算法

    2024年02月12日
    浏览(12)
  • 【LeetCode-面试经典150题-day23】

    【LeetCode-面试经典150题-day23】

    目录 108. 将有序数组转换为二叉搜索树  148.排序链表  427.建立四叉树  23.合并K个升序链表   108. 将有序数组转换为二叉搜索树 题意: 给你一个整数数组  nums  ,其中元素已经按  升序  排列,请你将其转换为一棵  高度平衡  二叉搜索树。 高度平衡  二叉树是一棵满足「

    2024年02月09日
    浏览(8)
  • LeetCode面试经典150题(day 1)

    LeetCode面试经典150题(day 1)

    LeetCode是一个免费刷题的一个网站,想要通过笔试的小伙伴可以每天坚持刷两道算法题。 接下来,每天我将更新LeetCode面试经典150题的其中两道算法题,一边巩固自己,一遍希望能帮助到有需要的小伙伴。 88.合并两个有序数组 给你两个按  非递减顺序  排列的整数数组  nu

    2024年02月11日
    浏览(10)
  • LeetCode面试经典150题(day 2)

    LeetCode面试经典150题(day 2)

    26. 删除有序数组中的重复项 难度: 简单    给你一个  升序排列  的数组  nums  ,请你  原地  删除重复出现的元素,使每个元素  只出现一次  ,返回删除后数组的新长度。元素的  相对顺序  应该保持  一致  。然后返回  nums  中唯一元素的个数。 考虑  nums  的唯一

    2024年02月11日
    浏览(10)
  • LeetCode150道面试经典题-- 加一(简单)

    LeetCode150道面试经典题-- 加一(简单)

    给你一个非负整数 x ,计算并返回  x  的 算术平方根 。 由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。 注意: 不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。 示例 1: 输入:x=4 输出:2   示例 2: 输入: x = 8 输出: 2 解释: 8 的

    2024年02月12日
    浏览(11)
  • LeetCode150道面试经典题-- 快乐数(简单)

    LeetCode150道面试经典题-- 快乐数(简单)

    编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」  定义为: 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。 如果这个过程 结果为  1,那么这个数就是快乐数。 如果

    2024年02月12日
    浏览(11)
  • leetcode每日一题——189.轮转数组(面试经典150题)

    189. 轮转数组 - 力扣(LeetCode) 给定一个整数数组  nums ,将数组中的元素 向右轮转  k   个位置 ,其中  k   是非负数。 示例1: 示例2: 1 = nums.length = 105 -231 = nums[i] = 231 - 1 0 = k = 105        对题目进行分析可知,我们需要根据轮转量k,将数组后面的k个元素按照原来的顺

    2024年02月12日
    浏览(12)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包