Hot 100 --- 二叉搜索树中第K小的元素
本文概览:本文以LeetCode题目"二叉搜索树中第K小的元素"为例,讲解如何利用BST中序遍历递增的性质,通过全局计数器在遍历过程中找到第K小的元素,并用-1作为标识实现找到即退出
一、题目

二、题目分析
这道题和上一篇"验证二叉搜索树"是同一个思路来的。由于是二叉搜索树,中序遍历的结果就是递增序列,所以中序遍历到第 k 个元素,就是第 K 小的元素
思路是通用的,但这个中序遍历需要多加点东西了:
- 全局计数器:必须知道当前遍历到第几个元素了,所以需要一个计数器
count,用属性记录就好了,这个是对象方法内全局统一的 - 找到即退出:当计数器到达 k 时,说明找到了目标元素,应该直接退出,不再继续遍历后面的节点
思路概览
Java 实现代码如下
1 | class Solution { |
思路简要说明
- 在中序遍历的基础上,增加一个全局计数器
count,每遍历一个节点就count++ - 用
-1作为标识:如果返回-1,说明这个节点不是最终值,继续遍历;只有count == k时才返回root.val(非-1) - 左子树遍历完后检查返回值,如果不是
-1,说明左子树已经找到答案,直接返回,不再处理当前节点和右子树
三、思路详解
中序遍历的递增性质
这和上一篇"验证二叉搜索树"是同一个起点:BST 的中序遍历(左→根→右)一定是严格递增的
1 | 5 |
所以找第 K 小的元素,就是中序遍历到第 k 个元素时返回它的值
两个要解决的问题
普通的中序遍历只是"遍历所有节点",但这道题有两个额外要求:
1. 需要计数——知道遍历到第几个了
每遍历到一个节点,计数器 count 加 1。用类的属性 count 来记录,这样在整个递归过程中是全局统一的,所有递归调用共享同一个计数器
2. 找到即退出——不要白干活
当 count == k 时,说明当前节点就是第 K 小的元素,直接返回它的值。不需要再继续遍历后面的节点了
-1 标识的设计
这里用 -1 作为"没找到"的标识:
- 返回
-1:说明这个节点(及其子树)里没有找到第 K 小的元素,调用方应该继续往别处找 - 返回非
-1:说明找到了第 K 小的元素,直接层层返回,不再继续遍历
为什么能这样设计?因为题目保证树中至少有 k 个节点,所以最终一定会找到。-1 只是一个中间状态的标识,表示"这条路还没找到"
代码执行流程
以这棵树为例,找第 3 小的元素(k=3):
1 | 5 |
逐层看递归过程:
1 | 调用 getKthSmallest(5, 3) |
可以看到,一旦在节点 4 处 count == k,返回值 4 就会层层传递回去,每一层都因为 left != -1 或 right != -1 直接返回,不再继续遍历。节点 5、6、7 都没有被访问到——这就是"找到即退出"的效果
递归结构回顾
和普通中序遍历的结构对比:
| 普通中序遍历 | 本题 | |
|---|---|---|
| 出口 | if (root == null) return; |
if (root == null) return -1; |
| 左子树 | inorder(root.left, res); |
int left = ...; if (left != -1) return left; |
| 当前节点 | res.add(root.val); |
count++; if (count == k) return root.val; |
| 右子树 | inorder(root.right, res); |
int right = ...; if (right != -1) return right; |
| 返回值 | 无(void) | int(-1 或 root.val) |
核心区别就两点:多了计数器 count,以及用返回值 -1 来实现"找到即退出"
复杂度分析
- 时间复杂度:最坏 O(n),但要找到第 k 小的元素最多遍历 k 个节点,所以实际是 O(k)
- 空间复杂度:O(h),h 为树高,递归栈开销
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 青山木!

