【LeetCode】230. 二叉搜索树中第K小的元素 Kth Smallest Element in a BST
- 作者: 负雪明烛
- id: fuxuemingzhu
- 个人博客: http://fuxuemingzhu.cn/
- 公众号:负雪明烛
- 本文关键词:算法题,刷题,Leetcode, 力扣,二叉搜索树,BST,第 k 小的元素,Python, C++, Java
题目地址:https://leetcode.com/problems/kth-smallest-element-in-a-bst/#/description
题目描述
Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.
Note:
- You may assume k is always valid, 1 ≤ k ≤ BST’s total elements.
Example 1:
Input: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
2
Output: 1
Example 2:
Input: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
Output: 3
Follow up:
- What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine?
题目大意
找出一个BST中第K小的数字是多少。
解题方法
各位题友大家好! 我是负雪明烛。
今天题目重点只有一个:二叉搜索树(BST)。
遇到二叉搜索树,立刻想到这句话:
「二叉搜索树(BST)的中序遍历是有序的」。
这是解决所有二叉搜索树问题的关键。
题目要求 BST 中第 k 小的元素,等价于求 BST 中序遍历的第 k 个元素。
分享二叉树遍历的模板:先序、中序、后序遍历方式的区别在于把「执行操作」放在两个递归函数的位置。
伪代码在下面。
- 先序遍历:
def dfs(root):
if not root:
return
执行操作
dfs(root.left)
dfs(root.right)
- 中序遍历:
def dfs(root):
if not root:
return
dfs(root.left)
执行操作
dfs(root.right)
- 后序遍历:
def dfs(root):
if not root:
return
dfs(root.left)
dfs(root.right)
执行操作
本题是使用了中序遍历,所以把「执行操作」这一步改成自己想要的代码。
于是有了下面两种写法。
方法一:数组保存中序遍历结果
这个方法是最直观的,也最不容易出错的。
- 先中序遍历,把结果放在数组中;
- 最后返回数组的第 k 个元素。
对应的代码如下,二叉树的各种遍历方式是基本功,务必要掌握。
Java 代码如下:
public class Solution {
List<Integer> list;
public int kthSmallest(TreeNode root, int k) {
list = new ArrayList<Integer>();
dfs(root);
return list.get(k - 1);
}
public void dfs(TreeNode root){
if(root == null){
return;
}
dfs(root.left);
list.add(root.val);
dfs(root.right);
}
}
C++ 代码如下:
class Solution {
public:
int kthSmallest(TreeNode* root, int k) {
vector<int> res;
dfs(root, res);
return res[k - 1];
}
void dfs(TreeNode* root, vector<int>& res) {
if (!root) return;
dfs(root->left, res);
res.push_back(root->val);
dfs(root->right, res);
}
};
Python 语言如下:
class Solution(object):
def kthSmallest(self, root, k):
res = []
self.dfs(root, res)
return res[k - 1]
def dfs(self, root, res):
if not root: return
self.dfs(root.left, res)
res.append(root.val)
self.dfs(root.right, res)
复杂度分析:
- 时间复杂度:
O
(
N
)
O(N)
O(N),因为每个节点只访问了一次;
- 空间复杂度:
O
(
N
)
O(N)
O(N),因为需要数组保存二叉树的每个节点值。
方法二:只保存第 k 个节点
在方法一中,我们保存了整个中序遍历数组,比较浪费空间。
其实我们只需要知道,在中序遍历的时候,第 k 个被访问的节点即可。访问到第 k 个节点后,递归终止,后面的节点就不用访问了。
下图展示了中序遍历过程中的节点访问顺序。

具体的做法中,我们需要需要两个变量:
- 用一个全局变量保存最终的结果;
- 用一个全局变量保存当前访问到第几个节点。
如果不使用全局变量,而是使用函数传参,需要注意「值传递」和「引用传递」的区别:
值传递:每个递归的内部都需要对同一个变量修改,如果用普通函数的传参,对于 int 型的参数,使用的是值传递,即拷贝了一份传到了函数里面。那么函数里面对 int 型的修改不会影响外边的变量。
使用全局变量,可以保证递归函数的每次修改都是反映到全局的,从而保证遍历到第 k 个的时候,所有的递归立刻停止。
Java 代码如下:
public class Solution {
int res;
int count;
public int kthSmallest(TreeNode root, int k) {
res = 0;
count = k;
dfs(root);
return res;
}
public void dfs(TreeNode root){
if(root == null){
return;
}
dfs(root.left);
count--;
if(count == 0){
res = root.val;
return;
}
dfs(root.right);
}
}
C++ 代码如下:
class Solution {
public:
int kthSmallest(TreeNode* root, int k) {
count = k;
dfs(root);
return res;
}
void dfs(TreeNode* root) {
if (!root) return;
dfs(root->left);
count -= 1;
if (count == 0) {
res = root->val;
return;
}
dfs(root->right);
}
private:
int res;
int count;
};
Python 代码如下:
class Solution(object):
def kthSmallest(self, root, k):
self.res = 0
self.count = k
self.dfs(root)
return self.res
def dfs(self, root):
if not root: return
self.dfs(root.left)
self.count -= 1
if self.count == 0:
self.res = root.val
return
self.dfs(root.right)
复杂度分析:
- 时间复杂度:
O
(
k
)
O(k)
O(k),因为只访问了前
k
k
k 个节点;
- 空间复杂度:
O
(
h
)
O(h)
O(h),其中
h
h
h 为树的高度,因为递归用了系统栈,而栈的深度最多只有树的高度。
迭代
待补。
总结
- 二叉树的多种遍历方式必须要掌握。
- 一定切记:二叉搜索树的中序遍历是有序的。
- 另外建议刚开始刷题的朋友,不妨从二叉树上手。
类似题目:
我是 @负雪明烛 ,刷算法题 1000 多道,写了 1000 多篇算法题解,收获阅读量 300 万。
关注我,你将不会错过我的精彩动画题解、面试题分享、组队刷题活动,进入主页 @负雪明烛 右侧有刷题组织,从此刷题不再孤单。
- 在刷题的时候,如果你不知道该怎么刷题,可以看 LeetCode 应该怎么刷?
- 如果你觉得题目太多,想在短时间内快速提高,可以看 LeetCode 最经典的 100 道题。
日期
2017 年 4 月 10 日
2019 年 1 月 25 日 —— 这学期最后一个工作日
2021 年 10 月 17 日
【LeetCode】230. 二叉搜索树中第K小的元素 Kth Smallest Element in a BST的更多相关文章
- LeetCode 230. 二叉搜索树中第K小的元素(Kth Smallest Element in a BST)
230. 二叉搜索树中第K小的元素 230. Kth Smallest Element in a BST 题目描述 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的 ...
- [Swift]LeetCode230. 二叉搜索树中第K小的元素 | Kth Smallest Element in a BST
Given a binary search tree, write a function kthSmallest to find the kth smallest element in it. Not ...
- Java实现 LeetCode 230 二叉搜索树中第K小的元素
230. 二叉搜索树中第K小的元素 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 说明: 你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数. ...
- [LeetCode]230. 二叉搜索树中第K小的元素(BST)(中序遍历)、530. 二叉搜索树的最小绝对差(BST)(中序遍历)
题目230. 二叉搜索树中第K小的元素 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 题解 中序遍历BST,得到有序序列,返回有序序列的k-1号元素. 代 ...
- LeetCode——230. 二叉搜索树中第K小的元素
给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 说明: 你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数. 示例 1: 输入: root = ...
- leetcode 230 二叉搜索树中第K小的元素
方法1:统计每个节点的子节点数目,当k>左子树节点数目时向左子树搜索,k=左子树节点数目时返回根节点,否则向右子树搜索. 方法2:递归中序遍历,这里开了O(n)空间的数组. class Solu ...
- LeetCode 230. 二叉搜索树中第K小的元素(Kth Smallest Element in a BST)
题目描述 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 说明:你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数. 示例 1: 输入: roo ...
- leetcode 230. 二叉搜索树中第K小的元素(C++)
给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 说明:你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数. 示例 1: 输入: root = [ ...
- leetcode 230二叉搜索树中第k小的元素
通过stack进行中序遍历迭代,timeO(k),spaceO(1) /** * Definition for a binary tree node. * struct TreeNode { * in ...
随机推荐
- 嵌入式Linux利用ppp实现4G模块联网
https://blog.csdn.net/qq361294382/article/details/52136126 https://blog.csdn.net/qq361294382/article ...
- C语言中不用 + 和 - 求两个数之和
(二)解题 题目大意:不用+或者-实现两个整数的加法 解题思路:不用+或者-,就自然想到位运算,无非就是与或非来实现二进制的加法 首先,我们来看一位二进制的加法和异或运算 A B A&B A^ ...
- Shell 指定行处理head、tail、sed
目录 Shell 指定行处理 head.tail.sed head 前几行 tail sed 删除.替换.新增.选取 案例 删除行 插入行 查看某行 替换某行 部分数据的查找并替换 读写操作 Shel ...
- Vue函数防抖和函数节流
函数防抖(debounce) 应用场景 登录.发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防 ...
- 学会这几步,简单集成视频编辑原子能力SDK
华为视频编辑服务6.2.0版本上线后,我们为大家带来了两大变化:分别是丰富多样的AI能力和灵活选择的集成方式.为让开发者更快上手使用,今天小编带来了视频编辑原子能力SDK的具体集成方法.快来试试吧! ...
- Fllin(七)【Flink CDC实践】
目录 FlinkCDC 1.简介 2.依赖 3.flink stream api 4.flink sql 5.自定义反序列化器 6.打包测试 FlinkCDC 1.简介 CDC是Change Data ...
- 零基础学习java------21---------动态代理,java8新特性(lambda, stream,DateApi)
1. 动态代理 在一个方法前后加内容,最简单直观的方法就是直接在代码上加内容(如数据库中的事务),但这样写不够灵活,并且代码可维护性差,所以就需要引入动态代理 1.1 静态代理实现 在讲动态代理之前, ...
- oracle异常处理——ORA-01000:超出打开游标最大数
oracle异常处理--ORA-01000:超出打开游标最大数https://www.cnblogs.com/zhaosj/p/4309352.htmlhttps://blog.csdn.net/u0 ...
- ybatis中查询出多个以key,value的属性记录,封装成一个map返回的方法
可以采用值做映射,也可以不采用映射方式 <resultMap id="configMap" type="java.util.Map" > <r ...
- mysql_取分组后的前几行值
--方法一: select a.id,a.SName,a.ClsNo,a.Score from Table1 a left join Table1 b on a.ClsNo=b.ClsNo and a ...