• 作者: 负雪明烛
  • 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 个元素。

分享二叉树遍历的模板:先序、中序、后序遍历方式的区别在于把「执行操作」放在两个递归函数的位置。

伪代码在下面。

  1. 先序遍历:
def dfs(root):
if not root:
return
执行操作
dfs(root.left)
dfs(root.right)
  1. 中序遍历:
def dfs(root):
if not root:
return
dfs(root.left)
执行操作
dfs(root.right)
  1. 后序遍历:
def dfs(root):
if not root:
return
dfs(root.left)
dfs(root.right)
执行操作

本题是使用了中序遍历,所以把「执行操作」这一步改成自己想要的代码。

于是有了下面两种写法。

方法一:数组保存中序遍历结果

这个方法是最直观的,也最不容易出错的。

  1. 先中序遍历,把结果放在数组中;
  2. 最后返回数组的第 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 个节点后,递归终止,后面的节点就不用访问了。

下图展示了中序遍历过程中的节点访问顺序。

具体的做法中,我们需要需要两个变量:

  1. 用一个全局变量保存最终的结果;
  2. 用一个全局变量保存当前访问到第几个节点。

如果不使用全局变量,而是使用函数传参,需要注意「值传递」和「引用传递」的区别:

值传递:每个递归的内部都需要对同一个变量修改,如果用普通函数的传参,对于 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 为树的高度,因为递归用了系统栈,而栈的深度最多只有树的高度。

迭代

待补。

总结

  1. 二叉树的多种遍历方式必须要掌握。
  2. 一定切记:二叉搜索树的中序遍历是有序的。
  3. 另外建议刚开始刷题的朋友,不妨从二叉树上手。

类似题目:


我是 @负雪明烛 ,刷算法题 1000 多道,写了 1000 多篇算法题解,收获阅读量 300 万。

关注我,你将不会错过我的精彩动画题解、面试题分享、组队刷题活动,进入主页 @负雪明烛 右侧有刷题组织,从此刷题不再孤单。

日期

2017 年 4 月 10 日
2019 年 1 月 25 日 —— 这学期最后一个工作日
2021 年 10 月 17 日

【LeetCode】230. 二叉搜索树中第K小的元素 Kth Smallest Element in a BST的更多相关文章

  1. LeetCode 230. 二叉搜索树中第K小的元素(Kth Smallest Element in a BST)

    230. 二叉搜索树中第K小的元素 230. Kth Smallest Element in a BST 题目描述 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的 ...

  2. [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 ...

  3. Java实现 LeetCode 230 二叉搜索树中第K小的元素

    230. 二叉搜索树中第K小的元素 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 说明: 你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数. ...

  4. [LeetCode]230. 二叉搜索树中第K小的元素(BST)(中序遍历)、530. 二叉搜索树的最小绝对差(BST)(中序遍历)

    题目230. 二叉搜索树中第K小的元素 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 题解 中序遍历BST,得到有序序列,返回有序序列的k-1号元素. 代 ...

  5. LeetCode——230. 二叉搜索树中第K小的元素

    给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 说明: 你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数. 示例 1: 输入: root = ...

  6. leetcode 230 二叉搜索树中第K小的元素

    方法1:统计每个节点的子节点数目,当k>左子树节点数目时向左子树搜索,k=左子树节点数目时返回根节点,否则向右子树搜索. 方法2:递归中序遍历,这里开了O(n)空间的数组. class Solu ...

  7. LeetCode 230. 二叉搜索树中第K小的元素(Kth Smallest Element in a BST)

    题目描述 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 说明:你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数. 示例 1: 输入: roo ...

  8. leetcode 230. 二叉搜索树中第K小的元素(C++)

    给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 说明:你可以假设 k 总是有效的,1 ≤ k ≤ 二叉搜索树元素个数. 示例 1: 输入: root = [ ...

  9. leetcode 230二叉搜索树中第k小的元素

    通过stack进行中序遍历迭代,timeO(k),spaceO(1) /** * Definition for a binary tree node. * struct TreeNode { * in ...

随机推荐

  1. Notepad++—显示代码对齐是使用了制表符还是空格

    使用Notepad++打开脚本,勾选"显示空格与制表符",此时你会看到代码对齐使用了制表符与空格 右箭头:TAB:空格:点: 参考:https://www.cnblogs.com/ ...

  2. SQL-Union、Union ALL合并两个或多个 SELECT 语句的结果集

    UNION 操作符用于合并两个或多个 SELECT 语句的结果集. 请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列.列也必须拥有相似的数据类型.同时,每条 SELECT 语句中的列 ...

  3. Python中类的相关介绍

    本文主要介绍python中类的概念性内容,如类的定义.说明及简单使用 1. 类的简单介绍 1 # -*- coding:utf-8 -*- 2 # Author:Wong Du 3 4 ''' 5 - ...

  4. Excel-给出指定数值的日期 date()

    DATE函数 函数名称:DATE 主要功能:给出指定数值的日期. 使用格式:DATE(year,month,day) 参数说明:year为指定的年份数值(小于9999):month为指定的月份数值(可 ...

  5. jsp的动态包含和静态包含

    jsp的动态包含和静态包含 例如:提取一个公共的页面(top.jsp)到/WEB-INF/jsp/common/目录下 动态包含: 被包含的页面也会独立编译,生成字节码文件,一般包含页面信息频繁变化的 ...

  6. tensorboard No dashboards are active for the current data set.

    修改一下启动命令时的路径 位置示例: 命令为   E:\PYTHON_PROJECT\testTF\inceptionV1_net\log>tensorboard --logdir=TEC4FN ...

  7. A Child's History of England.52

    'Arthur,' said the King, with his wicked eyes more on the stone floor than on his nephew, 'will you ...

  8. flink01--------1.flink简介 2.flink安装 3. flink提交任务的2种方式 4. 4flink的快速入门 5.source 6 常用算子(keyBy,max/min,maxBy/minBy,connect,union,split+select)

    1. flink简介 1.1 什么是flink Apache Flink是一个分布式大数据处理引擎,可以对有限数据流(如离线数据)和无限流数据及逆行有状态计算(不太懂).可以部署在各种集群环境,对各种 ...

  9. CSS相关,手画三角形,正方形,扇形

    三角形 实现一个三角形 <!DOCTYPE html> <html> <head> <title>三角形</title> <style ...

  10. 【原创】Altium生成Gerber时跳出The Film is too small for this PCB的解决办法

    在用altium Designer画板子的时候,要生成gerber文件的时候,会出错,出现这样的提示框:"The Film is too small for this PCB" 原 ...