LeetCode题练习与总结:二叉搜索树中第K小的元素--230

206 篇文章 0 订阅
127 篇文章 0 订阅

一、题目描述

给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 小的元素(从 1 开始计数)。

示例 1:

输入:root = [3,1,4,null,2], k = 1
输出:1

示例 2:

输入:root = [5,3,6,2,4,null,null,1], k = 3
输出:3

提示:

  • 树中的节点数为 n 。
  • 1 <= k <= n <= 10^4
  • 0 <= Node.val <= 10^4

二、解题思路

由于给定的树是一个二叉搜索树(BST),它的性质是左子树的所有节点值小于根节点值,右子树的所有节点值大于根节点值。因此,可以通过中序遍历(In-order Traversal)的方式来访问树的所有节点,这样可以得到一个递增的节点值序列。

我们可以使用一个计数器来记录已经访问过的节点数,当计数器的值等于 k 时,当前访问的节点值即为第 k 小的元素。

以下是具体的步骤:

  1. 初始化一个计数器 count 为 0。
  2. 进行中序遍历。
  3. 每访问一个节点,计数器 count 加 1。
  4. 当 count 等于 k 时,返回当前节点的值。

三、具体代码

class Solution {
    private int count = 0;
    private int result = 0;

    public int kthSmallest(TreeNode root, int k) {
        inOrderTraversal(root, k);
        return result;
    }

    private void inOrderTraversal(TreeNode node, int k) {
        if (node == null || count >= k) {
            return;
        }
        // 遍历左子树
        inOrderTraversal(node.left, k);
        // 访问当前节点
        count++;
        if (count == k) {
            result = node.val;
            return;
        }
        // 遍历右子树
        inOrderTraversal(node.right, k);
    }
}

在这段代码中,inOrderTraversal 方法是递归地进行中序遍历。当 count 等于 k 时,我们找到了第 k 小的元素,并将其值赋给 result。由于我们在找到第 k 小的元素后立即返回,所以不会继续不必要的遍历,这提高了算法的效率。

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 时间复杂度:O(n),其中 n 是二叉搜索树中的节点数量。

    • 对于每个节点,我们只访问一次,因为一旦找到第 k 小的元素,我们就会停止遍历。
    • 在最坏的情况下,如果第 k 小的元素是树中的最后一个元素,我们需要遍历所有的 n 个节点。
  • 最好情况时间复杂度:O(k),如果第 k 小的元素位于二叉搜索树的前 k 个节点中,我们只需要遍历 k 个节点。

2. 空间复杂度
  • 空间复杂度:O(h),其中 h 是二叉搜索树的高度。

    • 这是因为在递归过程中,我们需要维护一个递归栈。在最坏的情况下,递归栈的大小与树的高度相同,即树退化成一条链表时。
    • 由于二叉搜索树可能退化成链表,所以空间复杂度取决于树的高度,而不是节点数量。
  • 最坏情况空间复杂度:O(n),当树完全不平衡,即树的高度等于节点数量 n。

  • 平均情况空间复杂度:O(log n),在平衡的二叉搜索树中,树的高度大约是 log n,因此递归栈的空间复杂度是 O(log n)。

这些分析假设树的结构是未知的,可能是不平衡的,也可能是完全平衡的。在实际情况中,如果已知树是平衡的,那么平均情况的空间复杂度更可能是适用的。

五、总结知识点

  • 二叉树遍历

    • 代码实现了二叉树的中序遍历(In-order Traversal),这是一种深度优先搜索(DFS)的特例。
    • 中序遍历二叉搜索树会按照节点的递增顺序访问所有节点。
  • 递归

    • inOrderTraversal 方法是递归的,它调用自身来遍历左子树和右子树。
    • 递归是处理树结构数据的一种常用方法。
  • 二叉搜索树性质

    • 二叉搜索树的左子树中的所有节点的值小于根节点的值,右子树中的所有节点的值大于根节点的值。
    • 利用这一性质,中序遍历可以按顺序访问所有节点。
  • 计数器

    • 使用一个私有变量 count 来记录已经访问过的节点数量。
    • 当 count 等于 k 时,意味着找到了第 k 小的元素。
  • 全局变量

    • 使用私有变量 result 来存储找到的第 k 小的元素值。
    • 由于 result 在递归过程中被修改,因此它必须是类的实例变量,而不是局部变量。
  • 递归终止条件

    • 当访问到 null 节点或者已经找到第 k 小的元素时(即 count >= k),递归会终止。
  • 返回值

    • kthSmallest 方法返回找到的第 k 小的元素值。
    • inOrderTraversal 方法没有返回值,因为它的作用是通过修改实例变量 result 来存储结果。
  • 递归栈

    • 虽然代码中没有直接使用栈数据结构,但递归调用实际上是通过调用栈来实现的。
    • 每次递归调用都会在调用栈上添加一个新的帧。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一直学习永不止步

谢谢您的鼓励,我会再接再厉的!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值