Day62:二叉搜索树的第k个结点
剑指Offer_编程题——二叉搜索树的第k个结点
题目描述:
给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
具体要求:
时间限制: C/C++ 1秒,其他语言2秒 空间限制: C/C++32M,其他语言64M
具体实现:
背景知识介绍: 在前面的文章中我们详细的介绍了二叉搜索树的相关概念,接下来我们介绍二叉搜索树的具体应用。二叉排序树又称二叉查找树(二叉搜索树),它或是一棵空的二叉树,或是具有下列性质的二叉树: 1、若它的左子树不空,则左子树上所有节点的值均小于根节点的值 2、若它的右子树不空,则右子树上所有节点的值均大于根节点的值 3、它的左右子树也都是二叉排序树 对一个二叉树进行中序遍历,如果是单调递增的,则可以说明这个树是二叉搜索树。二叉搜索树的基本操作有:查找 key(其中:右树的值 > 根节点的值 > 左树的值)、插入、删除等。以下就是一颗典型的搜索二叉树:
思路一: 本题很明显考察的就是二叉树的中序遍历,因此在做题之前,我们先给大家详细介绍二叉树的后序遍历。在前面的文章中给大家介绍过二叉树的遍历。因此我们就不详细给大家介绍,如果想要了解二叉树的遍历可以看此文章。根据我们前面对二叉搜索树的介绍,本题很明显用到中序遍历,具体的实现思路如下: 1、二叉搜素树的中序遍历访问队列,自然的满足升序排序的条件。 2、中序遍历二叉搜索树,暂存输出队列。 3、 从保存的输出队列中找到满足条件的值。 我们分别用java和python两种编程语言将其实现: 1、首先我们用java将其实现:
import java.util.ArrayList;
public class Solution{
ArrayList<TreeNode> arr = new ArrayList<>();
TreeNode KthNode(TreeNode pRoot, int k){
if(pRoot == null || k == 0)
return null;
inOrder(pRoot);
TreeNode tr = pRoot;
if(k <= arr.size()){
tr = arr.get(k - 1);
}else{
return null;
}
return tr;
}
public void inOrder(TreeNode root){
if(root == null)
return;
if(root.left != null)
inOrder(root.left);
arr.add(root);
if(root.right != null)
inOrder(root.right);
}
}
代码效果图如图所示:
正如前面说的那样,如果在牛客网中,我们可以直接通过,但是如果是本地的编译器,则还需要定义其结点,具体结点的实现定义用java实现如下:
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
TreeNode next = null;
TreeNode(int val) {
this.val = val;
}
}
2、接下来我们用python将其实现
class Solution:
def KthNode(self, pRoot, k):
if k <= 0:
return None
res = []
self.inOrder(pRoot, res)
if len(res) < k:
return None
return res[k - 1]
def inOrder(self, root, res):
if not root:
return
if root.left:
self.inOrder(root.left, res)
res.append(root)
if root.right:
self.inOrder(root.right, res)
代码效果图如图所示:
但是在本地编译器中我们还需要定义树结构才能正常运行,具体用python定义树结构实现如下:
class TreeNode:
def __init__(self, pNode):
self.val = x
self.left = None
self.right = None
思路二: 从上述的题目可知,本题实际就是考察中序遍历。不同之处仅仅在于:中序遍历返回二叉树中序遍历后所有节点的值的列表,而这道题返回中序遍历过程中填入列表的第k个节点。我们当然可以先对平衡二叉树进行中序遍历,在返回的列表中找到第k个节点;但很显然还有更直接的方式,即中序遍历到需要的位置后立即返回,而不需要遍历完整棵二叉树。具体过程如下: 1、改进思路1,不再暂存所有输出。 2、改为设置一个计数器。中序遍历过程中,累加计算访问过的节点数目,当计数器等于要求的k时,则返回该节点。 具体我们用java和python将其实现: 1、首先我们用java将其实现:
public class Solution{
int index = 0;
TreeNode KthNode(TreeNode root, int k){
if(root != null){
TreeNode node = KthNode(root.left, k);
if(node != null){
return node;
}
index++;
if(index == k){
return root;
}
node = KthNode(root.right, k);
if(node != null)
return node;
}
return null;
}
}
代码效果图如图所示:
2、接下来我们用Python将其实现:
class Solution:
count = 0
def KthNode(self, pRoot, k):
if not pRoot:
return None
node = self.KthNode(pRoot.left, k)
if node:
return node
self.count += 1
if self.count == k:
return pRoot
node = self.KthNode(pRoot.right, k)
if node:
return node
代码效果图如图所示:
思路三: 其实也是对思路一的改进,我们两种思路均是用的递归,我们思路三可以用非递归的方法实现中序遍历。接下来我们用java将其实现:
import java.util.Stack;
public class Solution{
int count = 0;
TreeNode KthNode(TreeNode pRoot, int k){
if(count > k || pRoot == null)
return null;
TreeNode p = pRoot;
Stack<TreeNode> LDRStack = new Stack<>();
TreeNode kthNode = null;
while(p != null || !LDRStack.isEmpty()){
while(p != null){
LDRStack.push(p);
p = p.left;
}
TreeNode node = LDRStack.pop();
System.out.println(node.val+",");
count++;
if(count == k){
kthNode = node;
break;
}
p = node.right;
}
return kthNode;
}
}
代码效果图如图所示:
总结
本题主要通过二叉树搜索树的第k个结点来考察我们对二叉搜索树的理解以及对二叉树中的中序遍历的掌握情况。本文给出了三种解题思路,实质上就是实现二叉树的中序遍历的过程,其中有递归,并且分别用python和java两种编程语言将其实现。另外也通过栈的“先进后出”的特性来实现二叉树中序遍历的非递归。因此,我们在做题的时候,应该多次尝试各种方法,扩展自己的思维,写出优质的代码。总之,我们要继续加油,争取早日找到工作,Good Luck!!!
参考文献
[1] 负雪明烛 [2] goddaniel [3] ouyangyanlan
- 人工智能、区块链、图灵测试……这30个大数据热词你真的都懂吗?
- Enterprise Library 4.1学习笔记4----缓存应用程序块
- 设置py文件的路径
- jenkins中通过git发版操作记录
- Enterprise Library 4.1学习笔记3----安全应用程序块
- mysql密码遗忘和登陆报错问题
- 新一轮发展趋势:城市智能化已经势不可挡
- Enterprise Library 4.1学习笔记2----数据访问程序块
- 微信小程序中用户唯一ID的获取
- Mysql备份系列(2)--mysqldump备份(全量+增量)方案操作记录
- Enterprise Library 4.1学习笔记1----配置应用程序块(c/s和b/s均适用)
- 简单账本-用完即走的微信小程序
- 新技术革命和新产业变革正进行 “互联网+大数据+人工智能+”时代正到来
- 微信小程序开发及相关设置小结
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Resolved versions for app (26.1.0) and test app (27.1.1) differ.
- APP 引导页、欢迎页运用
- 管道与重定向、文件查找-Linux每日一练(7)
- 软件包管理、计划任务-Linux每日一练(8)
- AkShare-能源数据-碳排放-湖北
- AkShare-能源数据-碳排放-广州
- AkShare-股票数据-次新股
- 问与答87: 如何根据列表内容在文件夹中查找图片并复制到另一个文件夹中?
- Java反射是什么?看这篇绝对会了!
- Vuejs 3.0 正式版发布!One Piece. 代号:海贼王
- ES6中模块导入遇到的问题及其解决办法
- 还在手写任务调度代码?试试这款可视化分布式调度框架!
- 3分钟搞定微信小程序类美团用户商家距离计算
- pytest封神之路第五步 参数化进阶
- 深入解读Vue修饰符sync