您的位置:首页 > 职场人生

面试精选:二叉树问题集锦

2017-06-24 10:26 543 查看

0.本文目录

本文目录

开篇明志

定义二叉树数据结构

二叉树的序列化和反序列化

前序遍历

中序遍历

后序遍历

二叉树层次广度优先遍历

二叉树深度优先遍历

二叉树最大深度

二叉树的最近公共祖先

二叉树的镜像
非递归实现

1.开篇明志

在上一篇《面试精选:链表问题集锦》中, 我总结了一些常见的有关链表的题目; 而本文将对有关二叉树的常见问题进行总结。

2.定义二叉树数据结构

public class TreeNode{
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int val){
this.val = val;
}
}


3.二叉树的序列化和反序列化

设计一个算法,并编写代码来序列化和反序列化二叉树。将树写入一个文件被称为“序列化”,读取文件后重建同样的二叉树被称为“反序列化”。

如何反序列化或序列化二叉树是没有限制的,你只需要确保可以将二叉树序列化为一个字符串,并且可以将字符串反序列化为原来的树结构。

样例

给出一个测试数据样例, 二叉树{3,9,20,#,#,15,7},表示如下的树结构:

3
/ \
9  20
/ \
15   5


//序列化
public String serialize(TreeNode root) {
if (root == null) {
return "#,";
}
String mid = root.val + ",";
String left = serialize(root.left);
String right = serialize(root.right);
mid += left + right;
return mid;
}

private String data = "";
//反序列化
public TreeNode deserialize(String data) {
this.data = data;
return desHelper();
}

public TreeNode desHelper() {
if (this.data.indexOf("#,") == 0) {
this.data = this.data.substring(this.data.indexOf(",") + 1);
return null;
}
String midVal = this.data.substring(0, this.data.indexOf(","));
TreeNode mid = new TreeNode(Integer.parseInt(midVal));
this.data = this.data.substring(this.data.indexOf(",") + 1);
TreeNode left = desHelper();
TreeNode right = desHelper();
mid.left = left;
mid.right = right;
return mid;
}


4.前序遍历

问题: 给出一棵二叉树,返回其节点值的前序遍历。

样例

给出一棵二叉树 {1,#,2,3},

1
\
2
/
3


返回 [1,2,3].

import java.util.ArrayList;
import java.util.Iterator;

public class PreOrderTraversal{
//二叉树的前序遍历
public static ArrayList<Integer> preOrderTraversal(TreeNode root){
ArrayList<Integer> result = new ArrayList<Integer>(15);

if(root == null)
return result;

result.add(root.val);//根
ArrayList<Integer> left = preOrderTraversal(root.left);//左
ArrayList<Integer> right = preOrderTraversal(root.right);//右

result.addAll(left);
result.addAll(right);
return result;
}
}


5.中序遍历

//二叉树中序遍历
public static ArrayList<Integer> inorderTraversal(TreeNode root){
ArrayList<Integer> result = new ArrayList<Integer>(15);

if(root == null)
return result;

ArrayList<Integer> left = inorderTraversal(root.left);
result.addAll(left);

result.add(root.val);

ArrayList<Integer> right = inorderTraversal(root.right);
result.addAll(right);

return result;
}


6.后序遍历

//二叉树后续遍历
public static ArrayList<Integer> postOrderTraversal(TreeNode root){
ArrayList<Integer> result = new ArrayList<Integer>(15);

if(root == null)
return result;

ArrayList<Integer> left = postOrderTraversal(root.left);
result.addAll(left);
ArrayList<Integer> right = postOrderTraversal(root.right);
result.addAll(right);

result. add(root.val);

return result;
}


7.二叉树层次[广度优先]遍历

广度优先搜索(Breadth First Search),又叫宽度优先搜索或横向优先搜索,是从根结点开始沿着树的宽度搜索遍历。

宽度搜索遍历, 其实就是所谓的层次遍历, 分层遍历。

public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) {
ArrayList result = new ArrayList();

if (root == null) {
return result;
}

Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);

while (!queue.isEmpty()) {
ArrayList<Integer> level = new ArrayList<Integer>();
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode head = queue.poll();
level.add(head.val);
if (head.left != null) {
queue.offer(head.left);
}
if (head.right != null) {
queue.offer(head.right);
}
}
result.add(level);
}

return result;
}


8.二叉树深度优先遍历

深度优先搜索(Depth First Search)是沿着树的深度遍历树的节点,尽可能深的搜索树的分支。

深度优先搜索二叉树是先访问根结点,然后遍历左子树接着是遍历右子树,因此我们可以利用堆栈的先进后出的特点,

先将右子树压栈,再将左子树压栈,这样左子树就位于栈顶,可以保证结点的左子树先与右子树被遍历。

//深度优先搜索
//利用栈, 先将右子树压入栈, 再将左子树压入栈
public static void DFS(TreeNode root){
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.push(root);

while(!stack.empty()){
TreeNode node = stack.peek();
System.out.println(node.val);

stack.pop();

if(node.right != null){
stack.push(node.right);
}

if(node.left != null){
stack.push(node.left);
}
}
}


9.二叉树最大深度

给定一个二叉树,找出其最大深度。

二叉树的深度为根节点到最远叶子节点的距离。

样例

给出一棵如下的二叉树:

1
/ \
2   3
/ \
4   5


这个二叉树的最大深度为3.

public static int maxDepth(TreeNode root){
if(root == null){
return 0;
}
//最大深度 + 1
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}


10.二叉树的最近公共祖先

给定一棵二叉树,找到两个节点的最近公共父节点(LCA)。

最近公共祖先是两个节点的公共的祖先节点且具有最大深度。

注意事项

假设给出的两个节点都在树中存在

样例

对于下面这棵二叉树

4
/ \
3   7
/ \
5   6

LCA(3, 5) = 4

LCA(5, 6) = 7

LCA(6, 7) = 7


// 在root为根的二叉树中找A,B的LCA:
// 如果找到了就返回这个LCA
// 如果只碰到A,就返回A
// 如果只碰到B,就返回B
// 如果都没有,就返回null
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode node1, TreeNode node2) {
if (root == null || root == node1 || root == node2) {
return root;
}

// Divide
TreeNode left = lowestCommonAncestor(root.left, node1, node2);
TreeNode right = lowestCommonAncestor(root.right, node1, node2);

// Conquer
if (left != null && right != null) {
return root;
}
if (left != null) {
return left;
}
if (right != null) {
return right;
}
return null;
}


11.二叉树的镜像

非递归实现

即使用循环实现

public static void mirrorNonRecurively(TreeNode root){
if(root == null)
return;

java.util.Stack<TreeNode> stack = new java.util.Stack<TreeNode>();

stack.push(root);

while(stack.size() > 0){
TreeNode node = stack.pop();
if(null != node.left || null != node.right){
TreeNode temp = node.left;
node.left = node.right;
node.right = temp;
}

if(null != node.left){
stack.push(node.left);
}

if(null != node.right){
stack.push(node.right);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: