LeetCode100之二叉搜索树中第K小的元素(230)--Java

1.问题描述

给定一个二叉搜索树的根节点 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小的元素

2.解题思路

这道题是要求我们求二叉搜索树中第K小的元素,熟悉树的遍历方式和二叉搜索树概念的读者,应该不难想到,如果我们使用中序遍历来遍历二叉搜索树,那我们将可以得到一个升序的有序序列。

所以这道题要求我们求第K小的元素,其实就是要求中序遍历的有序序列中的第K个元素而已。

理解了题意之后,我们就可以开始来操作了。一般我们的中序遍历使用递归来实现的,今天这里我提供另外一种实现遍历的方法,也就是迭代的方法。

这里,我们首先需要创建一个栈,用来辅助我们的遍历,后面我们会将节点和空节点一起放入栈中,空节点用作标记,只有被空节点标记的节点才会被遍历处理(换句话说,就是我们之处理空节点后的第一个节点)。

java 复制代码
        //用于辅助遍历
        Stack<TreeNode> stack = new Stack<>();

判断根节点是否为空,不为空则将根节点入栈,并定义一个计数遍历用于计数,方便我们找到第K个节点。

java 复制代码
        //栈不为空,将节点存入栈中
        if(root != null){
            stack.push(root);
        }
       //用于计数遍历了多少节点
        int count = 0;

接着,我们就可以用一个while循环开始遍历了,循环的结束条件是栈为空,栈空了自然就没有节点可以处理了。

java 复制代码
        //开始遍历
        while(!stack.isEmpty())

接下来,是while循环内的单层迭代逻辑。

我们从栈中取出栈顶的节点(node),判断该节点是否为空。

java 复制代码
          //从栈中取出一个节点
            TreeNode node = stack.pop();
            //判断该节点是否为空
            if(node != null){
               .....

            }else{
               .....
            }

栈顶节点(node)不为空,则不是待处理节点,我们要将它和它的左右节点放入栈中。这里,我们需要根据遍历的方法,确定节点放入栈中的顺序。由于我们是要中序遍历,处理节点的顺序是左根右,再加上栈是后进先出的,所以节点入栈的顺序应该是右根左。我们在存入左右节点时,要先判断左右节点是否为空,为空的话我们则不入栈,防止与空标记冲突混淆;在存入根节点之后,存入一个空节点用于将根节点标记为待处理节点,这样下一次弹出该空节点,就意味着要处理该根节点了。

java 复制代码
                //非空,继续往栈中放入节点
                //中序遍历-> 左 根 右
                //存入栈中的循序-> 右 根 左
                //右节点
                if(node.right != null){
                    stack.push(node.right);
                }
                //存入根节点
                stack.push(node);
                //存入空节点,用做标记
                stack.push(null);
                //左节点
                if(node.left != null){
                    stack.push(node.left);
                }

如果栈顶节点(node)为空,说明下一个节点是待处理节点。我们将待处理节点从栈顶取出,并让计数变量+1。接着判断计数变量是否等于K,如果等于K,说明我们找到了我们要的节点,直接将当前节点的值返回即可,如果不等于K,接着遍历。

java 复制代码
                  //为空,处理下一个节点
                //弹出待处理节点
                node = stack.pop();
                //计数+1
                count++;
                //判断是否为第K个被处理的节点
                if(count == k){
                    //是,返回结果
                    return node.val;
                }

如果遍历结束后,还是找不到第K小的元素,则直接返回-1。

java 复制代码
        return -1;

3.代码展示

java 复制代码
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int kthSmallest(TreeNode root, int k) {
        //用于辅助遍历
        Stack<TreeNode> stack = new Stack<>();
        //栈不为空,将节点存入栈中
        if(root != null){
            stack.push(root);
        }
        //用于计数遍历了多少节点
        int count = 0;
        //开始遍历
        while(!stack.isEmpty()){
            //从栈中取出一个节点
            TreeNode node = stack.pop();
            //判断该节点是否为空
            if(node != null){
                //非空,继续往栈中放入节点
                //中序遍历-> 左 根 右
                //存入栈中的循序-> 右 根 左
                //右节点
                if(node.right != null){
                    stack.push(node.right);
                }
                //存入根节点
                stack.push(node);
                //存入空节点,用做标记
                stack.push(null);
                //左节点
                if(node.left != null){
                    stack.push(node.left);
                }

            }else{
                //为空,处理下一个节点
                //弹出待处理节点
                node = stack.pop();
                //计数+1
                count++;
                //判断是否为第K个被处理的节点
                if(count == k){
                    //是,返回结果
                    return node.val;
                }
            }
        }
        return -1;
    }
}

4.总结

这道题考察的是二叉搜索树的特点和树的遍历方法,我在这里提供了使用迭代方法的中序遍历,这个迭代方法可以看成一个模版,和递归遍历差不多,递归遍历只需要改一下单层递归逻辑中的节点顺序,就可以实现不同方式的遍历,这里的迭代法也只需要改变一下存入栈中节点的顺序,就可以实现不同方式的遍历,注意在遍历时存入根节点的时候要加上一个空节点进行标记。

今天这道题就啰嗦这么多,祝大家刷题愉快~

相关推荐
昂子的博客2 分钟前
热门面试题第十天|Leetcode150. 逆波兰表达式求值 239. 滑动窗口最大值 347.前 K 个高频元素
算法
Forget the Dream17 分钟前
设计模式之迭代器模式
java·c++·设计模式·迭代器模式
大丈夫在世当日食一鲲25 分钟前
Java中用到的设计模式
java·开发语言·设计模式
A-Kamen29 分钟前
Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现与实战指南
java·spring boot·后端
练川31 分钟前
Stream特性(踩坑):惰性执行、不修改原始数据源
java·stream
狂奔小菜鸡36 分钟前
Java运行时数据区
java·jvm·后端
trymoLiu42 分钟前
SpringBoot 实现 RSA+AES 自动接口解密!
java·spring boot
卑微小文1 小时前
2025国内网络反爬新高度:代理IP智能轮换算法揭秘
后端·算法·架构
ChinaRainbowSea1 小时前
MySQL 索引的数据结构(详细说明)
java·数据结构·数据库·后端·mysql
33三 三like1 小时前
软件工程画图题
java·开发语言·软件工程