【二叉树】二叉搜索(BST)树验证、二叉搜索树中的搜索、二叉搜索树的最小绝对差

目录

什么是二叉搜索树:

1.二叉搜索树中的搜索

2.验证二叉搜索树: 

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


#学习记录#

今天我们来看看二叉搜索树的问题,

对应力扣:

1. 二叉搜索树中的搜索:700. 二叉搜索树中的搜索 - 力扣(LeetCode)

2.验证二叉搜索树:98. 验证二叉搜索树 - 力扣(LeetCode)

3.二叉搜索树的最小绝对差: 530. 二叉搜索树的最小绝对差 - 力扣(LeetCode)

什么是二叉搜索树:

🌟 二叉搜索树(Binary Search Tree,简称BST)是一种特殊的二叉树,它有一些独特的特性,非常适合用来存储数据并快速地进行查找、插入和删除操作。

二叉搜索树的基本概念:

  1. 结构特点:每个节点有最多两个子节点,通常被称为“左子节点”和“右子节点”。

  2. 排序规则

    • 每个节点的左子树只包含小于该节点的值。
    • 每个节点的右子树只包含大于该节点的值。
    • 没有两个节点拥有相同的值。
  3. 查找效率:由于二叉搜索树的排序特性,查找效率通常比较高。在最理想的情况下(树是平衡的),查找操作的时间复杂度为O(log n),其中n是树中节点的数量。

  4. 插入和删除:插入和删除操作需要维护二叉搜索树的排序规则,通常也是O(log n)的时间复杂度(在树平衡的情况下)。

举个例子:

            5
           / \
          3   8
         / \   \
        1   4   9

1.二叉搜索树中的搜索

题目描述:

搜索算法步骤:

  1. 开始于根节点:搜索操作从树的根节点开始。
  2. 比较搜索值:将搜索值与当前节点的值进行比较。
  3. 决定方向
    • 如果搜索值等于当前节点的值,搜索成功。
    • 如果搜索值小于当前节点的值,移动到左子节点继续搜索。
    • 如果搜索值大于当前节点的值,移动到右子节点继续搜索。
  4. 递归或迭代:重复上述过程,直到找到值或达到叶子节点(没有子节点的节点)。

效率

  • 在平衡的BST中,搜索操作的时间复杂度为O(log n),其中n是树中节点的数量。
  • 在最坏的情况下(树完全不平衡),时间复杂度可能退化为O(n)。
# 递归法
def searchBST(root, val):
    if root is None or val == root.val:
        return root
    if val < root.val:
        return searchBST(root.left, val)
    else:
        return searchBST(root.right, val)

除了递归法外,我们还可以使用迭代法,更好理解:

def searchBST(self, root, val):
    cur = root
    while cur is not None:
        if cur.val == val:
            break
        if val > cur.val:
            cur = cur.right
            continue
        if val < cur.val:
            cur = cur.left
            continue
    return cur

2.验证二叉搜索树: 

题目描述:

解题思路及方法

根据二叉树的特性,我们可以发现,当二叉树中序遍历(左中右)时,结果是从小到大的列表。那么我们最简单的方式就是将其保存在列表中,然后对列表进行判断。

我们先来回顾一下二叉树的中序遍历

# 递归
result = []
def inorder(root):
    if not root:
        return []
    inorder(root.left)      # 左
    result.append(root.val) # 中
    inorder(root.right)     # 右
# 力扣中写在方法内记得在方法前加上self

使用递归方法非常简洁

我们再回顾一下迭代法,这里需要调用栈来辅助我们进行迭代

# 二叉树的中序遍历(迭代)
def inorder(root):
    stack = []
    result = []
    cur = root
    while cur or stack:
        if cur:
            stack.append(cur)
            cur = cur.left
        else:
            cur = stack.pop()
            result.append(cur.val)
            cur = cur.right
    result result

复习过中序遍历后我们来撰写本题:

先来简单的,如果先求得中序列表再判断,代码为:

class Solution:
    def inorder(self, root):
        # 中序遍历
        if not root:
            return []
        return self.inorder(root.left) + [root.val] + self.inorder(root.right)
        # 这里对代码进行了精简

    def isSorted(self, lst):
        # 判断一个列表是否递增
        for i in range(1, len(lst)):
            if lst[i] <= lst[i - 1]:
                return False
        return True

    def isValidBST(self, root):
        # 判断是否是二叉搜索树
        return self.isSorted(self.inorder(root))

同时我们还可以在遍历的过程中进行判断,我们只需要比较前一个元素是够比当前元素大即可,这里我们需要提前设定一个pre

class Solution:
    def __init__(self):
        self.prev = None

    def inorder(self, root):
        # 中序遍历
        if not root:
            return True
        if not self.inorder(root.left):
            return False
        if self.prev and self.prev.val >= root.val:
            return False
        self.prev = root
        return self.inorder(root.right)

    def isValidBST(self, root):
        # 判断是否是二叉搜索树
        return self.inorder(root)

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

题目描述:

算法步骤:

  1. 中序遍历:对BST进行中序遍历,获得一个按升序排列的节点值列表。
  2. 计算相邻差值:遍历这个列表,计算相邻元素之间的差值。
  3. 找出最小差值:记录并更新这些差值中的最小值。

为什么使用中序遍历: 中序遍历BST会得到一个按升序排列的值序列,最小差值一定在相邻的两个值之间产生。这使得算法非常高效。

代码示例(Python):

class Solution:
    def getMinimumDifference(self, root):
        self.prev = None
        self.min_diff = float('inf')

        def inorder(node):
            if not node:
                return
            inorder(node.left)
            if self.prev is not None:
                self.min_diff = min(self.min_diff, node.val - self.prev.val)
            self.prev = node
            inorder(node.right)

        inorder(root)
        return self.min_diff

 以上,学习在于坚持和总结,共勉

  • 45
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值