给定一个二叉树的根结点root,请依次返回二叉树的先序,中序和后续遍历(二维数组的形式)。
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}*/
public class TreeToSequence {
public int[][] convert(TreeNode root) {
List<Integer> list1 = new ArrayList<Integer>();
List<Integer> list2 = new ArrayList<Integer>();
List<Integer> list3 = new ArrayList<Integer>();
qianxu(list1,root);
zhongxu(list2,root);
houxu(list3,root);
int[][] res = new int[3][list1.size()];
for(int i=0;i<list1.size();i++){
res[0][i] = list1.get(i);
res[1][i] = list2.get(i);
res[2][i] = list3.get(i);
}
return res;
}
private void qianxu(List<Integer> list,TreeNode tree){
if(tree==null)
return;
list.add(tree.val);
qianxu(list,tree.left);
qianxu(list,tree.right);
}
private void zhongxu(List<Integer> list,TreeNode tree){
if(tree==null)
return;
zhongxu(list,tree.left);
list.add(tree.val);
zhongxu(list,tree.right);
}
private void houxu(List<Integer> list,TreeNode tree){
if(tree==null)
return;
houxu(list,tree.left);
houxu(list,tree.right);
list.add(tree.val);
}
}
1.先序遍历思路:
(1)cur = root,cur 入栈,cur 出栈存入 list
(2)判断 cur 右孩子是否为空,不为空则入栈;再判断 cur 左孩子是否为空,不为空则入栈
(2)弹出栈顶存入 list ,cur = 栈顶节点,再重复步骤(2)(3)
2.中序遍历思路:
(1)cur = root,如果 cur 不为空则入栈,cur = cur.left,并重复(1)
(2)若 cur 为空,则弹出栈顶存入 list,并另 cur = cur.right;重复(1)(2)
3.后序遍历思路:
(1)定义两个节点 h = root ,c = 栈顶节点(初始为 null)
(2)tree入栈,c = tree;如果 c.left 不为空且 h != c.left 和 c.right,则 c 入栈
(3)否则若 c.right 不为空且 h != c.right,则 c 入栈
(4)若(2)(3)都不满足,则 h = c(栈顶节点),栈顶出栈存入 list ,重复(2)(3)(4)
public class TreeToSequence {
public int[][] convert(TreeNode root) {
List<Integer> list1 = new ArrayList<Integer>();
List<Integer> list2 = new ArrayList<Integer>();
List<Integer> list3 = new ArrayList<Integer>();
qianxu(list1,root);
zhongxu(list2,root);
houxu(list3,root);
int[][] res = new int[3][list1.size()];
for(int i=0;i<list1.size();i++){
res[0][i] = list1.get(i);
res[1][i] = list2.get(i);
res[2][i] = list3.get(i);
}
return res;
}
//前序遍历
private void qianxu(List<Integer> list,TreeNode tree){
if(tree==null)
return;
Stack<TreeNode> temp = new Stack<TreeNode>();
temp.push(tree);
while(!temp.empty()){
TreeNode cur = temp.pop();
list.add(cur.val);
if(cur.right!=null)
temp.push(cur.right);
if(cur.left!=null)
temp.push(cur.left);
}
}
//中序遍历
private void zhongxu(List<Integer> list,TreeNode tree){
if(tree==null)
return;
Stack<TreeNode> temp = new Stack<TreeNode>();
TreeNode cur = tree;
while(!temp.empty()||cur!=null){
if(cur!=null){
temp.push(cur);
cur = cur.left;
}else{
cur = temp.pop();
list.add(cur.val);
cur = cur.right;
}
}
}
//后序遍历
private void houxu(List<Integer> list,TreeNode tree){
if(tree==null)
return;
TreeNode h = tree;
TreeNode c = null;
Stack<TreeNode> temp = new Stack<TreeNode>();
temp.push(tree);
while(!temp.empty()){
c = temp.peek();
if(c.left!=null && (h!=c.left && h!=c.right)){
temp.push(c.left);
c = temp.peek();
}else if(c.right!=null && h!=c.right){
temp.push(c.right);
c = temp.peek();
}else{
h = c;
TreeNode tmp = temp.pop();
list.add(tmp.val);
}
}
}
}
有一棵二叉树,请设计一个算法,按照层次打印这棵二叉树
思路:
(1)将A出队,并将A的子孩子入队,更新nlast=A最后入队的子孩子(最右边的孩子);
(2)打印上次出队的A,并和last比较, 如果相同就打印换行,并更新last=nlast,如果不相同,则继续
import java.util.*;
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}*/
public class TreePrinter {
public int[][] printTree(TreeNode root) {
if(root==null)
return null;
TreeNode print = null;
TreeNode last = null;
TreeNode nlast = null;
ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> rows = new ArrayList<Integer>();
LinkedList<TreeNode> q = new LinkedList();
last = root;
q.offer(root);
while(!q.isEmpty()){
print = q.poll();
rows.add(print.val);
if(print.left!=null){
q.offer(print.left);
nlast = print.left;
}
if(print.right!=null){
q.offer(print.right);
nlast = print.right;
}
if(print == last){
res.add(rows);
rows = new ArrayList<Integer>();
last = nlast;
}
}
int[][] result = new int[res.size()][];
for(int i=0;i<res.size();i++){
result[i] = new int[res.get(i).size()];
for(int j=0;j<res.get(i).size();j++){
result[i][j] = res.get(i).get(j);
}
}
return result;
}
}
首先我们介绍二叉树先序序列化的方式,假设序列化的结果字符串为str,初始时str等于空字符串。先序遍历二叉树,如果遇到空节点,就在str的末尾加上“#!”,“#”表示这个节点为空,节点值不存在,当然你也可以用其他的特殊字符,“!”表示一个值的结束。如果遇到不为空的节点,假设节点值为3,就在str的末尾加上“3!”。现在请你实现树的先序序列化。
给定树的根结点root,请返回二叉树序列化后的字符串。
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}*/
public class TreeToString {
public String toString(TreeNode root) {
String res = "";
if(root==null)
return res;
TreeNode temp = root;
LinkedList<TreeNode> stack = new LinkedList<TreeNode>();//HashSet、HashMap、ArrayList、LinkedList均可接受null值
stack.push(temp);
while(!stack.isEmpty()){
TreeNode cur = stack.pop();
if(cur==null)
res = res + "#!";
else{
res = res + String.valueOf(cur.val) + "!";
stack.push(cur.right);
stack.push(cur.left);
}
}
return res;
}
}
有一棵二叉树,请设计一个算法判断这棵二叉树是否为平衡二叉树。
给定二叉树的根结点root,请返回一个bool值,代表这棵树是否为平衡二叉树。
思路:
(1)平衡二叉树:每个节点左右子树的高度差不超过 1,且空树也是平衡二叉树
(2)递归获得左右子树的深度,深度小于0或者左右子树深度差大于1,则直接返回false;否则继续递归,能返回树的深度(>=0)则说明是平衡二叉树
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}*/
public class CheckBalance {
public boolean check(TreeNode root) {
return getDepth(root)>=0;
}
private int getDepth(TreeNode root){
if(root==null)
return 0;
int left = getDepth(root.left);
int right = getDepth(root.right);
if(left<0||right<0)
return -1;
if(Math.abs(left-right)>1)
return -1;
return Math.max(left,right)+1;
}
}
有一棵二叉树,请设计一个算法判断它是否是完全二叉树。
给定二叉树的根结点root,请返回一个bool值代表它是否为完全二叉树。树的结点个数小于等于500。
思路:
(1)新建队列,按层遍历二叉树
(2)如果有节点的左孩子为空且右孩子不为空直接返回 false,如果左孩子不为空而右孩子为空,则此节点必须为叶子节点,如果不是叶子节点直接返回 false;循环中途没有返回 false,最后返回 true
public class CheckCompletion {
public boolean chk(TreeNode root) {
if(root==null)
return true;
Queue<TreeNode> q = new LinkedList<>();
boolean leaf = false;
q.offer(root);
while(!q.isEmpty()){
TreeNode temp = q.poll();
if((leaf&&(temp.left!=null||temp.right!=null))||(temp.left==null&&temp.right!=null))
return false;
if(temp.left!=null&&temp.right==null)
leaf = true;
if(temp.left!=null)
q.offer(temp.left);
if(temp.right!=null)
q.offer(temp.right);
}
return true;
}
}
请把纸条竖着放在桌⼦上,然后从纸条的下边向上⽅对折,压出折痕后再展 开。此时有1条折痕,突起的⽅向指向纸条的背⾯,这条折痕叫做“下”折痕 ;突起的⽅向指向纸条正⾯的折痕叫做“上”折痕。如果每次都从下边向上⽅ 对折,对折N次。请从上到下计算出所有折痕的⽅向。
给定折的次数n,请返回从上到下的折痕的数组,若为下折痕则对应元素为"down",若为上折痕则为"up".
测试样例:
1
返回:[“down”]
思路:第一次折纸,折痕为下折痕,第二次折纸,两边各多了下折痕和上折痕,相当于二叉树的左右孩子,每折纸一次节点就增加左右两个孩子。这是一颗满二叉树,而从上到下的折痕就是中序遍历这个二叉树。
public class FoldPaper {
public String[] foldPaper(int n) {
List<String> temp = new LinkedList<String>();
fold(1,n,true,temp);
String[] res = new String[temp.size()];
for(int i=0;i<temp.size();i++){
res[i] = temp.get(i);
}
return res;
}
private void fold(int i,int n,boolean flag,List<String> list){//flag用于判断左右孩子
if(i>n)
return;
fold(i+1,n,true,list);
if(flag)
list.add("down");
else
list.add("up");
fold(i+1,n,false,list);
}
}
一棵二叉树原本是搜索二叉树,但是其中有两个节点调换了位置,使得这棵二叉树不再是搜索二叉树,请找到这两个错误节点并返回他们的值。保证二叉树中结点的值各不相同。
给定一棵树的根结点,请返回两个调换了位置的值,其中小的值在前。
思路:
(1)中序遍历搜索二叉树,其结果是按照升序排列的
(2)遍历结果,如果只出现一次逆序则大小的节点都是错误节点;如果出现两次逆序,则第一次逆序的大节点,和第二次逆序的小节点才是两个错误节点。
public class FindErrorNode {
public int[] findError(TreeNode root) {
List<Integer> temp = new ArrayList<Integer>();
int[] res = new int[2];
int index = 0;//用于判断是第几次逆序
zhongxu(root,temp);
for(int i=0;i<temp.size()-1;i++){
if(temp.get(i)>temp.get(i+1)){
index++;
if(index==1){
res[1] = temp.get(i);
res[0] = temp.get(i+1);
}else
res[0] = temp.get(i+1);
}
}
return res;
}
public void zhongxu(TreeNode root,List<Integer> temp){
if(root==null)
return;
zhongxu(root.left,temp);
temp.add(root.val);
zhongxu(root.right,temp);
}
}
从二叉树的节点A出发,可以向上或者向下走,但沿途的节点只能经过一次,当到达节点B时,路径上的节点数叫作A到B的距离。对于给定的一棵二叉树,求整棵树上节点间的最大距离。
给定一个二叉树的头结点root,请返回最大距离。保证点数大于等于2小于等于500.
思路:
最大距离只可能有三种情况:
(1)root左子树的最大距离;
(2)root右子树的最大距离;
(3)root左子树上离root左孩子最远结点的距离,加上root自身;再加上root右子树上离root右孩子最远结点的距离
三个中,最大的即为所求
public class LongestDistance {
public int findLongest(TreeNode root) {
int[] res = new int[1];
houxu(root,res);
return res[0];
}
private int houxu(TreeNode root,int[] res){
if(root==null)
return 0;
int left = houxu(root.left,res);
int right = houxu(root.right,res);
res[0] = Math.max(res[0],left+right+1);
return Math.max(left,right)+1;
}
}
有一棵二叉树,其中所有节点的值都不一样,找到含有节点最多的搜索二叉子树,并返回这棵子树的头节点.
给定二叉树的头结点root,请返回所求的头结点,若出现多个节点最多的子树,返回头结点权值最大的。
思路:
二叉搜索树:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
(1)整体过程为二叉树的后序遍历;
(2) 遍历到当前结点记作cur时,先遍历cur的左子树并收集4个信息:分别是左子树上,最大搜索二叉树的头结点、结点数、树上最大值和树上最小值。再遍历cur的右子树,收集以上四个信息。
(3)根据步骤2所收集的信息,判断是否满足:是否以cur为头的子树,整体都是搜索二叉树,如果满足,就返回cur。如果不满足,就返回左子树和右子树各自最大搜索二叉树中,节点数较多的头结点。
public class MaxSubtree {
public TreeNode getMax(TreeNode root) {
int[] temp = new int[3];
return houxu(root,temp);
}
private TreeNode houxu(TreeNode root,int[] temp){
if(root==null){
temp[0]=Integer.MIN_VALUE;
temp[1]=Integer.MAX_VALUE;
temp[2]=0;
return null;
}
TreeNode left = houxu(root.left,temp);
int l_max = temp[0];//最大值
int l_min = temp[1];//最小值
int l_num = temp[2];//节点数
TreeNode right = houxu(root.right,temp);
int r_max = temp[0];
int r_min = temp[1];
int r_num = temp[2];
//递归到最后temp[0],temp[1]中存着的是节点的最大值最小值,初始r_max==Integer.MIN_VALUE,l_min(Integer.MAX_VALUE)
temp[0] = Math.max(r_max,root.val);
temp[1] = Math.min(l_min,root.val);
if(left==root.left && right==root.right && l_max<root.val && r_min>root.val){
temp[2] = l_num+r_num+1;
return root;
}
temp[2] = Math.max(l_num,r_num);//保存大的节点数
return l_num>r_num?left:right;
}
}