从一段简单算法题来谈二叉查找树(BST)的基础算法
先给出一道很简单,喜闻乐见的二叉树算法题:
给出一个二叉查找树和一个目标值,如果其中有两个元素的和等于目标值则返回真,否则返回假。
例如:
Input:
5
/ \
3 6
/ \ \
2 4 7 Target = 9 Output: TrueInput:
5
/ \
3 6
/ \ \
2 4 7 Target = 28 Output: False
什么是二叉树?
二叉树是每个节点最多有两个子树的树结构。
什么是二叉查找树(binary search tree)
二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
二叉树的遍历
1.先序遍历(pre-order)
首先访问根结点然后遍历左子树,最后遍历右子树。在遍历左、右子树时,仍然先访问根结点,然后遍历左子树,最后遍历右子树,如果二叉树为空则返回。 2.后序遍历( post-order )
后序遍历首先遍历左子树,然后遍历右子树,最后访问根结点,在遍历左、右子树时,仍然先遍历左子树,然后遍历右子树,最后遍历根结点。 3.中序遍历(in-order)
中序遍历首先遍历左子树,然后访问根节点,然后遍历右子树。
举个例子:
先序遍历节点遍历顺序: A B D H I K E C F G J L
后序遍历节点遍历顺序: H K I D E B F L J G C A
中序遍历节点遍历顺序: H D I K B E A F C J L G
算法题解法
1.使用HashSet
最简单的解法就是遍历整个树,然后得到所有的节点对来判断他们是否能相加得到目标值k。但是我们稍微考虑一下缓存,这个方案还能提高一些。
如果两个元素的和等于k,即x+y=k,并且我们已经知道x是已经存在于树的,我们只要检索y是否也在树的节点里即可,即y=k-x。基于这个简单的缓存,我们可以在每一步去遍历这棵树的两个方向(左子树和右子树)。我们使用一个集合来存遍历过程中被遍历过的元素。
对于每一个当前的节点,有值p,我们去检查k-p是否存在于集合中。如果存在的话,我们可以得到存在2个元素的值等于k的结论。否则,我们继续把这个值存进集合。
如果遍历了整棵树后,没有这样的p值,那就证明不存在2个元素的值相加等于k。
代码如下:
public class Solution {
public boolean findTarget(TreeNode root, int k) {
Set<Integer> set = new HashSet();
return find(root, k, set);
}
public boolean find(TreeNode root, int k, Set < Integer > set) {
if (root == null)
return false;
if (set.contains(k - root.val))
return true;
set.add(root.val);
return find(root.left, k, set) || find(root.right, k, set);
}
}
//时间复杂度为 O(n),空间复杂度也为O(n).
2.使用BFS和HashSet.
在这个解法中,使用HashSet的想法和解法1是一样的。但是我们在遍历的时候使用广度优先算法(Breadth First Search),这是一个在树的遍历算法中很常用的算法。BFS的方法如如下总结的一样。我们在开始的时候把根节点放进一个队列。
我们还是会用到如上解法的一个集合。然后在每一步我们会这么做:
1.从队列queue的头部去除一个元素p。
2.判断k-p是否存在于集合中。如果是,返回true。
3.否则,把这个元素p加到集合中。然后,把这个节点的左右子节点加到队列queue的末尾。
4.继续1-3步骤,直到队列为空。
5.如果队列为空,则返回false。
照这个步骤,我们一层一层的循环了整个树。
代码如下:
public class Solution {
public boolean findTarget(TreeNode root, int k) {
Set<Integer> set = new HashSet();
Queue<TreeNode> queue = new LinkedList();
queue.add(root);
while (!queue.isEmpty()) {
if (queue.peek() != null) {
TreeNode node = queue.remove();
if (set.contains(k - node.val))
return true;
set.add(node.val);
queue.add(node.right);
queue.add(node.left);
} else
queue.remove();
}
return false;
}
}
//时间复杂度为 O(n),空间复杂度也为O(n).
3.使用BST
在这个解法中,我们要充分利用这个树是一个二叉搜索树。现在,我们知道一个树的中序遍历会得到一个递增的节点集。如此一来,我们可以对这棵树进行中序排序,然后把结果存进一个数组,这个数组的元素按照升序的顺序排列。
上面的步骤做好以后,我们使用l和r两个指针指向数组的开头和结尾。然后,我们这么做:
1.判断l和r指向的节点的值的和是否等于k。如果是,立马返回true。
2.如果他们的和小于k,l移向下一个元素。我们需要得到更大的和,那我们只有提高我们更小的那个值。
3.如果他们的和大于k,r移向上一个元素。我们需要得到更小的和,那我们只有减少我们更大的那个值。
4.循环执行1-3步,直到l和r指针相遇。
5.如果l和r指针相遇,则返回false.
public class Solution {
public boolean findTarget(TreeNode root, int k) {
List<Integer> list = new ArrayList();
inorder(root, list);
int l = 0, r = list.size() - 1;
while (l < r) {
int sum = list.get(l) + list.get(r);
if (sum == k)
return true;
if (sum < k)
l++;
else
r--;
}
return false;
}
public void inorder(TreeNode root, List < Integer > list) {
if (root == null)
return;
inorder(root.left, list);
list.add(root.val);
inorder(root.right, list);
}
}
//时间复杂度为 O(n),空间复杂度也为O(n).
至于广度优先算法和深度优先算法,以后有机会再展开吧。
从一段简单算法题来谈二叉查找树(BST)的基础算法的更多相关文章
- LeetCode算法题-Minimum Distance Between BST Nodes(Java实现-四种解法)
这是悦乐书的第314次更新,第335篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第183题(顺位题号是783).给定具有根节点值的二叉搜索树(BST),返回树中任何两个 ...
- php笔试算法题:顺时针打印矩阵坐标-蛇形算法
这几天参加面试,本来笔试比较简单,但是在面试的时候,技术面试官说让我现场写一个算法,顺时针打印矩阵的坐标,如图所示 顺序为,0,1,2,3,4,9,14,19,24,23,22,21,20,15,10 ...
- 笔试算法题(52):简介 - KMP算法(D.E. Knuth, J.H. Morris, V.R. Pratt Algorithm)
议题:KMP算法(D.E. Knuth, J.H. Morris, V.R. Pratt Algorithm) 分析: KMP算法用于在一个主串中找出特定的字符或者模式串.现在假设主串为长度n的数组T ...
- 前端如何应对笔试算法题?(用node编程)
用nodeJs写算法题 咱们前端使用算法的地方不多,但是为了校招笔试,不得不针对算法题去练习呀! 好不容易下定决心 攻克算法题.发现js并不能像c语言一样自建输入输出流.只能回去学习c语言了吗?其实不 ...
- python每日经典算法题5(基础题)+1(中难题)
现在,越来越多的公司面试以及考验面试对算法要求都提高了一个层次,从现在,我讲每日抽出时间进行5+1算法题讲解,5是指基础题,1是指1道中等偏难.希望能够让大家熟练掌握python的语法结构已经一些高级 ...
- Java在算法题中的输入问题
Java在算法题中的输入问题 在写算法题的时候,经常因为数据的输入问题而导致卡壳,其中最常见的就是数据输入无法结束. 1.给定范围,确定输入几个数据 直接使用普通的Scanner输入数据范围,然后使用 ...
- 简单的算法题, Find Minimum in Rotated Sorted Array 的Python实现。
简单的算法题, Find Minimum in Rotated Sorted Array 的Python实现. 题目: Suppose a sorted array is rotated at som ...
- SDUT OJ 数据结构实验之串一:KMP简单应用 && 浅谈对看毛片算法的理解
数据结构实验之串一:KMP简单应用 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Discuss Problem Descr ...
- 简单的PHP算法题
简单的PHP算法题 目录 1.只根据n值打印n个0 2.根据n值打印一行 0101010101010101010101…… 3.根据n值实现1 00 111 0000 11111…… 4.根据n值实现 ...
随机推荐
- #ifdef 的使用
1. _DEBUG #ifdef DEBUG的理解 首先需要注意的是,只有当前项目工作在 Debug(调试模式)(而不是Release(发布))设置下时编译器提供的宏定义.对于 visual stud ...
- 【计算机视觉】OpenCV中直方图处理函数简述
计算直方图calcHist 直方图是对数据集合的统计 ,并将统计结果分布于一系列提前定义的bins中.这里的数据不只指的是灰度值 ,统计数据可能是不论什么能有效描写叙述图像的特征. 如果有一个矩阵包括 ...
- js进阶 10-6 jquery中的属性选择器有哪些
js进阶 10-6 jquery中的属性选择器有哪些 一.总结 一句话总结: 1.第一遍能学会么? 一遍是肯定学不会的,要多学几遍,所以想着怎么加快速度,减少学习的遍数 2.属性选择器是干嘛的? 选择 ...
- Android View框架的measure机制
概述 Android中View框架的工作机制中,主要有三个过程: 1.View树的測量(measure)Android View框架的measure机制 2.View树的布局(layout) Andr ...
- xCode中怎样保存自己的代码块
在开发iOS的过程中.xCode肯定是用得最多的工具.没有之中的一个.由于苹果官方提供的就这一个平台,尽管没有竞争对手,但秉承苹果一贯的注重细节的原则,xCode还是一款相当不错的IDE. 作为一名i ...
- 【codeforces 782C】Andryusha and Colored Balloons
[题目链接]:http://codeforces.com/contest/782/problem/C [题意] 给你一棵树 让你满足要求 ->任意相连的3个节点的颜色不能相同 的情况下进行染色 ...
- java取奇偶数的基本练习
public class JiOu { public static void main(String[] args) { int a = 11; System.out.println("这个 ...
- spring boot 生成 war 包有一个war.original是什么?
两个坑 .war.original 生成这种格式的文件,是因为在开启了二次打包.具体可以看这里 修改入口文件的配置 , 官方文档看这里 类似下面的代码,要继承SpringBootServletInit ...
- 【足迹C++primer】49、超载,更改,运营商
超载,更改.运营商 Conversion Operators 转换操作符 operator type() const Conversions to an array or a function typ ...
- 【record】11.7..11.13
好少
