先给出一道很简单,喜闻乐见的二叉树算法题:

给出一个二叉查找树和一个目标值,如果其中有两个元素的和等于目标值则返回真,否则返回假。

例如:

Input:
5
/ \
3 6
/ \ \
2 4 7 Target = 9 Output: True
Input:
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)的基础算法的更多相关文章

  1. LeetCode算法题-Minimum Distance Between BST Nodes(Java实现-四种解法)

    这是悦乐书的第314次更新,第335篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第183题(顺位题号是783).给定具有根节点值的二叉搜索树(BST),返回树中任何两个 ...

  2. php笔试算法题:顺时针打印矩阵坐标-蛇形算法

    这几天参加面试,本来笔试比较简单,但是在面试的时候,技术面试官说让我现场写一个算法,顺时针打印矩阵的坐标,如图所示 顺序为,0,1,2,3,4,9,14,19,24,23,22,21,20,15,10 ...

  3. 笔试算法题(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 ...

  4. 前端如何应对笔试算法题?(用node编程)

    用nodeJs写算法题 咱们前端使用算法的地方不多,但是为了校招笔试,不得不针对算法题去练习呀! 好不容易下定决心 攻克算法题.发现js并不能像c语言一样自建输入输出流.只能回去学习c语言了吗?其实不 ...

  5. python每日经典算法题5(基础题)+1(中难题)

    现在,越来越多的公司面试以及考验面试对算法要求都提高了一个层次,从现在,我讲每日抽出时间进行5+1算法题讲解,5是指基础题,1是指1道中等偏难.希望能够让大家熟练掌握python的语法结构已经一些高级 ...

  6. Java在算法题中的输入问题

    Java在算法题中的输入问题 在写算法题的时候,经常因为数据的输入问题而导致卡壳,其中最常见的就是数据输入无法结束. 1.给定范围,确定输入几个数据 直接使用普通的Scanner输入数据范围,然后使用 ...

  7. 简单的算法题, Find Minimum in Rotated Sorted Array 的Python实现。

    简单的算法题, Find Minimum in Rotated Sorted Array 的Python实现. 题目: Suppose a sorted array is rotated at som ...

  8. SDUT OJ 数据结构实验之串一:KMP简单应用 && 浅谈对看毛片算法的理解

    数据结构实验之串一:KMP简单应用 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Discuss Problem Descr ...

  9. 简单的PHP算法题

    简单的PHP算法题 目录 1.只根据n值打印n个0 2.根据n值打印一行 0101010101010101010101…… 3.根据n值实现1 00 111 0000 11111…… 4.根据n值实现 ...

随机推荐

  1. Tricks(四十九)—— 按 batch 访问越界的解决办法

    使用 min 函数指定访问的最终位置,本质上是增加一个条件判断: done = false; batch_size = 10000; idx = 1; while ~done idx_end = mi ...

  2. 前端工具WebStorm好在哪里?(带详细破解教程)

    前端工具WebStorm好在哪里?(带详细破解教程) 一.总结 1.WebStorm对html特别是HTML5和JS的智能提示简直堪称大神. 2.WebStorm足够的轻量级. 3.WebStorm对 ...

  3. vs 错误提示及解决方案

    错误: 应输入";" 错误原因,宏展开出现错误:

  4. 卡特兰(Catalan)数列

    卡特兰数又称卡塔兰数,英文名 Catalan number,是组合数学中一个常出现在各种计数问题中出现的数列.以比利时的数学家欧仁·查理·卡塔兰 (1814–1894)的名字来命名,其前几项为 : 1 ...

  5. [Ramda] Get Deeply Nested Properties Safely with Ramda's path and pathOr Functions

    In this lesson we'll see how Ramda's path and pathOr functions can be used to safely access a deeply ...

  6. [React] Pass Data To Event Handlers with Partial Function Application

    In this lesson we’ll see how to pass an item’s id value in an event handler and get the state to ref ...

  7. 关于用WebView或手机浏览器打开连接问题

    1.通常情况下 大家可能都想使用WebView打开网页内部链接而不想再调用手机浏览器,我们可以通过以下两种方法实现: (1)为WebView设置一个WebViewClient,并重写shouldOve ...

  8. ios9 xcode7以后编译需要进行的几项设置

    http://blog.csdn.net/hero82748274/article/details/48629461 1.库后缀变了:.dylib->tbd libsqlite3.0.dylib ...

  9. 最新版Butterknife plugin支持butterknife7.0.1和兼容butterknife 6.1.0及下面

    JakeWharton 的butterknife帮我们有效的攻克了findViewById及各种view的监听事件泛滥的问题,极大的简化了代码,假设使用了android Studio开发的配上avas ...

  10. Linux虚拟文件系统(VFS)学习

    虚拟文件系统(Virtual Filesystem)也可称之为虚拟文件系统转换(Virtual Filesystem Switch),是一个内核软件层,用来处理与Unix标准文件系统相关的全部系统调用 ...