# 0230. 二叉搜索树中第K小的元素 ## 题目地址(230. 二叉搜索树中第K小的元素) <https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst/> ## 题目描述 ``` <pre class="calibre18">``` 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素。 说明: 你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数。 示例 1: 输入: root = [3,1,4,null,2], k = 1 3 / \ 1 4 \ 2 输出: 1 示例 2: 输入: root = [5,3,6,2,4,null,null,1], k = 3 5 / \ 3 6 / \ 2 4 / 1 输出: 3 进阶: 如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化 kthSmallest 函数? ``` ``` ## 前置知识 - 中序遍历 ## 公司 - 阿里 - 腾讯 - 百度 - 字节 ## 思路 解法一: 由于‘中序遍历一个二叉查找树(BST)的结果是一个有序数组’ ,因此我们只需要在遍历到第k个,返回当前元素即可。 中序遍历相关思路请查看[binary-tree-traversal](binary-tree-traversal.html) 解法二: 联想到二叉搜索树的性质,root 大于左子树,小于右子树,如果左子树的节点数目等于 K-1,那么 root 就是结果,否则如果左子树节点数目小于 K-1,那么结果必然在右子树,否则就在左子树。 因此在搜索的时候同时返回节点数目,跟 K 做对比,就能得出结果了。 ## 关键点解析 - 中序遍历 ## 代码 解法一: JavaScript Code: ``` <pre class="calibre18">``` <span class="hljs-title">/* * @lc app=leetcode id=230 lang=javascript * * [230] Kth Smallest Element in a BST */</span> <span class="hljs-title">/** * Definition for a binary tree node. * function TreeNode(val) { * this.val = val; * this.left = this.right = null; * } */</span> <span class="hljs-title">/** * @param {TreeNode} root * @param {number} k * @return {number} */</span> <span class="hljs-keyword">var</span> kthSmallest = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">root, k</span>) </span>{ <span class="hljs-keyword">const</span> stack = [root]; <span class="hljs-keyword">let</span> cur = root; <span class="hljs-keyword">let</span> i = <span class="hljs-params">0</span>; <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">insertAllLefts</span>(<span class="hljs-params">cur</span>) </span>{ <span class="hljs-keyword">while</span>(cur && cur.left) { <span class="hljs-keyword">const</span> l = cur.left; stack.push(l); cur = l; } } insertAllLefts(cur); <span class="hljs-keyword">while</span>(cur = stack.pop()) { i++; <span class="hljs-keyword">if</span> (i === k) <span class="hljs-keyword">return</span> cur.val; <span class="hljs-keyword">const</span> r = cur.right; <span class="hljs-keyword">if</span> (r) { stack.push(r); insertAllLefts(r); } } <span class="hljs-keyword">return</span> <span class="hljs-params">-1</span>; }; ``` ``` Java Code: ``` <pre class="calibre18">``` <span class="hljs-title">/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> count = <span class="hljs-params">1</span>; <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> res; <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">KthSmallest</span> <span class="hljs-params">(TreeNode root, <span class="hljs-keyword">int</span> k)</span> </span>{ inorder(root, k); <span class="hljs-keyword">return</span> res; } <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">inorder</span> <span class="hljs-params">(TreeNode root, <span class="hljs-keyword">int</span> k)</span> </span>{ <span class="hljs-keyword">if</span> (root == <span class="hljs-keyword">null</span>) <span class="hljs-keyword">return</span>; inorder(root.left, k); <span class="hljs-keyword">if</span> (count++ == k) { res = root.val; <span class="hljs-keyword">return</span>; } inorder(root.right, k); } ``` ``` 解法二: JavaScript Code: ``` <pre class="calibre18">``` <span class="hljs-title">/** * Definition for a binary tree node. * function TreeNode(val) { * this.val = val; * this.left = this.right = null; * } */</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">nodeCount</span>(<span class="hljs-params">node</span>) </span>{ <span class="hljs-keyword">if</span> (node === <span class="hljs-params">null</span>) <span class="hljs-keyword">return</span> <span class="hljs-params">0</span>; <span class="hljs-keyword">const</span> l = nodeCount(node.left); <span class="hljs-keyword">const</span> r = nodeCount(node.right); <span class="hljs-keyword">return</span> <span class="hljs-params">1</span> + l + r; } <span class="hljs-title">/** * @param {TreeNode} root * @param {number} k * @return {number} */</span> <span class="hljs-keyword">var</span> kthSmallest = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">root, k</span>) </span>{ <span class="hljs-keyword">const</span> c = nodeCount(root.left); <span class="hljs-keyword">if</span> (c === k - <span class="hljs-params">1</span>) <span class="hljs-keyword">return</span> root.val; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (c < k - <span class="hljs-params">1</span>) <span class="hljs-keyword">return</span> kthSmallest(root.right, k - c - <span class="hljs-params">1</span>); <span class="hljs-keyword">return</span> kthSmallest(root.left, k) }; ``` ``` **复杂度分析** - 时间复杂度:O(N)O(N)O(N) - 空间复杂度:O(N)O(N)O(N) ## 扩展 这道题有一个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?` 建议大家思考一下。 大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:<https://github.com/azl397985856/leetcode> 。 目前已经 37K star 啦。 大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。 ![](https://img.kancloud.cn/cf/0f/cf0fc0dd21e94b443dd8bca6cc15b34b_900x500.jpg)