LeetCode刷题--- 二叉搜索树中第K小的元素

个人主页元清加油_【C++】,【C语言】,【数据结构与算法】-CSDN博客

个人专栏


前言:这个专栏主要讲述递归递归、搜索与回溯算法,所以下面题目主要也是这些算法做的  

我讲述题目会把讲解部分分为3个部分:
1、题目解析

2、算法原理思路讲解

3、代码实现


注意:这道题目涉及到二叉搜索树的内容 ,若有不懂的可以参考下面这篇文章 

数据结构:二叉搜索树-CSDN博客


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

题目链接:二叉搜索树中第K小的元素

题目

给定一个二叉搜索树的根节点 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 <= 104
  • 0 <= Node.val <= 104

进阶:如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化算法?


解法

题目解析

题目意思很简单,给我们一颗二叉搜索树,我们找出第 k 个最小的值(从 1 开始)

二叉搜索树有如下特性:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

 算法原理思路讲解  

解法一:

依靠二叉搜索树的特性:中序遍历为有序

思路:创建一个全局变量 v ,中序遍历整个二叉树,将搜索二叉树的值存入 v 中,然后再返回 v[k-1] 即可


解法二:

解法一虽然也可以通过,上述解法不仅使⽤⼤量额外空间存储数据,并且会将所有的结点都遍历⼀遍我们没有必要遍历整个二叉搜索树。

但是,我们可以根据中序遍历的过程,只需扫描前 k 个结点即可。
思路:因此,我们可以创建⼀个全局的计数器 count,将其初始化为 k,每遍历⼀个节点就将 count--。直到某次递归的时候,count 的值等于 0 ,说明此时的结点就是我们要找的结果。
算法流程
1.定义⼀个全局的变量 count,在主函数中初始化为 k 的值
递归函数的设计

void dfs(TreeNode* root);
2.递归函数流程(中序遍历)
(1)递归出⼝:root == nullptr 或 count=0 的时候,返回 
(2)先递归判断左⼦树,count--
(3)判断 count 是否为0,若为 0 则把 val 值赋给 ret

以上思路就讲解完了,大家可以先自己先做一下 


代码实现 

解法一

  • 时间复杂度:预处理的时间复杂度为 O(N),其中 N 是树中结点的总数;我们需要遍历树中所有结点来统计以每个结点为根结点的子树的结点数。搜索的时间复杂度为 O(H),其中 H 是树的高度;当树是平衡树时,时间复杂度取得最小值 O(log⁡N);当树是线性树时,时间复杂度取得最大值 O(N)。
  • 空间复杂度:O(N),用于存储以每个结点为根结点的子树的结点数。
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution 
{
public:
    vector<int> v;
 
    void dfs(TreeNode* root)
    {
        if (root == nullptr)
        {
            return;
        }
 
        dfs(root->left);
        
        v.push_back(root->val);
 
        dfs(root->right);
 
    }

    int kthSmallest(TreeNode* root, int k) 
    {
        dfs(root);

        return v[k-1];
    }
};


解法二

  • 时间复杂度:O(H+k),其中 H 是树的高度。在开始遍历之前,我们需要 O(H) 到达叶结点。当树是平衡树时,时间复杂度取得最小值 O(log⁡N+k);当树是线性树(树中每个结点都只有一个子结点或没有子结点)时,时间复杂度取得最大值 O(N+k)。
  • 空间复杂度:O(1)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int count;
    int ret;

    void dfs(TreeNode* root)
    {
        if(root == nullptr || count == 0) return;
        dfs(root->left);
        count--;
        if(count == 0) ret = root->val;
        dfs(root->right);
    }

    int kthSmallest(TreeNode* root, int k) 
    {
        count = k;
        dfs(root);
        return ret;
    }
};

最近更新

  1. TCP协议是安全的吗?

    2023-12-14 14:24:03       19 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-14 14:24:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-14 14:24:03       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-14 14:24:03       20 阅读

热门阅读

  1. 计算机网络链路层(期末、考研)

    2023-12-14 14:24:03       46 阅读
  2. 新浪股票接口代码

    2023-12-14 14:24:03       32 阅读
  3. python代码示例

    2023-12-14 14:24:03       40 阅读
  4. Golang 领域驱动设计(DDD)最佳实践

    2023-12-14 14:24:03       38 阅读
  5. 数据结构--栈

    2023-12-14 14:24:03       38 阅读
  6. Cmap数据以及L1000介绍

    2023-12-14 14:24:03       48 阅读
  7. ES6之函数新增的扩展

    2023-12-14 14:24:03       37 阅读
  8. Vue3 中的 Proxy--读懂ES6中的Proxy

    2023-12-14 14:24:03       34 阅读