二叉树的操作算法是笔试面试中较为常见的题目。
本文将着重介绍平时面试中常见的关于二叉树的应用题目,马上要进行秋招了。希望对你们有帮助 _
编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。
输入包括1行字符串,长度不超过100。
可能有多组测试数据,对于每组数据, 输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个空格。 每个输出结果占一行。
输入: abc##de#g##f###
输出:c b e g d f a
首先我们先来看一下示例输入的二叉树的形状
我们首先需要做的是创建一个二叉树类,用于建立一个新的二叉树
class TreeNode1 {
char val;
TreeNode1 left;
TreeNode1 right;
TreeNode1() {}
TreeNode1(char val) {
this.val = val;
}
TreeNode1(char val, TreeNode1 left, TreeNode1 right) {
this.val = val;
this.left = left;
this.right = right;
}
}
接下来我们需要
代码实现如下:
public static TreeNode1 creatTree(String str) {
TreeNode1 root = null;
if (str.charAt(i) != '#') {
root = new TreeNode1(str.charAt(i));
i++;
root.left = creatTree(str);
root.right = creatTree(str);
} else {
i++;
}
return root;
}
然后根据题意我们还需要进行一个中序遍历,这里我就不做赘述了,又不懂的小伙伴可以去看一下博主对于【数据结构】二叉数的存储与基本操作的实现的讲解
实现如下:
public static void inorder(TreeNode1 root) {
if (root == null) {
return;
}
inorder(root.left);
System.out.print(root.val + " ");
inorder(root.right);
}
}
import java.util.Scanner;
class TreeNode1 {
char val;
TreeNode1 left;
TreeNode1 right;
TreeNode1() {}
TreeNode1(char val) {
this.val = val;
}
TreeNode1(char val, TreeNode1 left, TreeNode1 right) {
this.val = val;
this.left = left;
this.right = right;
}
}
public class Main {
public static int i = 0;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNextLine()) { // 注意 while 处理多个 case
i = 0;
String st = in.nextLine();
TreeNode1 root = new TreeNode1();
root = creatTree(st);
inorder(root);
}
}
public static TreeNode1 creatTree(String str) {
TreeNode1 root = null;
if (str.charAt(i) != '#') {
root = new TreeNode1(str.charAt(i));
i++;
root.left = creatTree(str);
root.right = creatTree(str);
} else {
i++;
}
return root;
}
public static void inorder(TreeNode1 root) {
if (root == null) {
return;
}
inorder(root.left);
System.out.print(root.val + " ");
inorder(root.right);
}
}
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
}
本题博主提供两种解题思路
我们发现:
我们建立两个栈:
然后我们只需要对两栈元素进行出栈进行比对就好了,最先相等的就为我们的最近公共祖先
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(p == root || q == root) {
return root;
}
if(root == null) {
return null;
}
TreeNode l = lowestCommonAncestor(root.left,p,q);
TreeNode r = lowestCommonAncestor(root.right,p,q);
if(l != null && r != null) {
return root;
} else if(l != null) {
return l;
} else if(r != null) {
return r;
}
return null;
}
}
class Solution {
public boolean getPath(TreeNode root, TreeNode node,
Deque<TreeNode> stack) {
if(root == null || node == null)return false;
stack.push(root);
//放完之后 要检查
if(root == node) return true;
boolean ret1 = getPath(root.left,node,stack);
if(ret1) return true;
boolean ret2 = getPath(root.right,node,stack);
if(ret2) return true;
stack.pop();
return false;
}
public TreeNode lowestCommonAncestor2(TreeNode root, TreeNode p, TreeNode q) {
//1、两个栈当中 存储好数据
Deque<TreeNode> stack1 = new LinkedList<>();
getPath(root,p,stack1);
Deque<TreeNode> stack2 = new LinkedList<>();
getPath(root,q,stack2);
//2、判断栈的大小
int size1 = stack1.size();
int size2 = stack2.size();
if(size1 > size2) {
int size = size1-size2;
while (size != 0) {
stack1.pop();
size--;
}
}else {
int size = size2-size1;
while (size != 0) {
stack2.pop();
size--;
}
}
//栈里面数据的个数 是一样的
while (!stack1.isEmpty() && !stack2.isEmpty()) {
if(stack1.peek() != stack2.peek()) {
stack1.pop();
stack2.pop();
}else {
return stack1.peek();
}
}
return null;
}
}
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
/**
* 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 TreeNode buildTree(int[] preorder, int[] inorder) {
}
}
我们知道前序遍历里面第一个存储的是我们的根节点
那我们就可以在我们中序遍历中找到该结点,则该结点两边就为该根节点的左右子树
对于任意一颗树而言,前序遍历的形式总是
[ 根节点, [左子树的前序遍历结果], [右子树的前序遍历结果] ]
即根节点总是前序遍历中的第一个节点。而中序遍历的形式总是
[ [左子树的中序遍历结果], 根节点, [右子树的中序遍历结果] ]
只要我们在中序遍历中定位到根节点,那么我们就可以分别知道左子树和右子树中的节点数目。由于同一颗子树的前序遍历和中序遍历的长度显然是相同的,因此我们就可以对应到前序遍历的结果中,对上述形式中的所有左右括号进行定位。
这样以来,我们就知道了左子树的前序遍历和中序遍历结果,以及右子树的前序遍历和中序遍历结果,我们就可以递归地对构造出左子树和右子树,再将这两颗子树接到根节点的左右位置。
我们的做法是这样的
我们对前序遍历结果进行下标利用下标 i 遍历,并放入到二叉树中
对中序遍历的元素设两个下标,一个记录最左边,一个记录最右边
对前序遍历里的每一个元素我们会在中序遍历里进行查找,找到后
我们的inbegin与inend在左右子树里又会有新的指向
然后我们利用递归的思想,对所有元素进行遍历
结束条件为inend < inbengin
/**
* 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 i = 0;
public TreeNode buildTree(int[] preorder, int[] inorder) {
return buildTreeChild(preorder,inorder,0,inorder.length-1);
}
public TreeNode buildTreeChild(int[] preorder, int[] inorder,
int inbegin,int inend) {
if(inbegin > inend) {
return null;
}
TreeNode root = new TreeNode(preorder[i]);
//找到当前根,在中序遍历的位置
int rootIndex = findIndex(inorder,inbegin,inend,preorder[i]);
i++;
root.left = buildTreeChild(preorder,inorder,inbegin,rootIndex-1);
root.right = buildTreeChild(preorder,inorder,rootIndex+1,inend);
return root;
}
private int findIndex( int[] inorder,int inbegin,int inend, int key) {
for(int i = inbegin;i <= inend; i++) {
if(inorder[i] == key) {
return i;
}
}
return -1;
}
}
与从前序与中序遍历序列构造二叉树实现类似,这里不再做过多赘述
代码实现:
class Solution2 {
public int i = 0;
public TreeNode buildTree(int[] inorder, int[] postorder) {
i = postorder.length-1;
return buildTreeChild(postorder,inorder,0,inorder.length-1);
}
public TreeNode buildTreeChild(int[] postorder, int[] inorder,
int inbegin,int inend) {
if(inbegin > inend) {
return null;
}
TreeNode root = new TreeNode(postorder[i]);
//找到当前根,在中序遍历的位置
int rootIndex = findIndex(inorder,inbegin,inend,postorder[i]);
i--;
root.right = buildTreeChild(postorder,inorder,rootIndex+1,inend);
root.left = buildTreeChild(postorder,inorder,inbegin,rootIndex-1);
return root;
}
private int findIndex( int[] inorder,int inbegin,int inend, int key) {
for(int i = inbegin;i <= inend; i++) {
if(inorder[i] == key) {
return i;
}
}
return -1;
}
}
关于《【数据结构】 二叉树面试题讲解->贰》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!