二叉树相关题:
1、二叉树递归套路:分左右子树收集信息,最后做消息整合,分别向左子树和右子树要信息
(1)二叉树节点的最大距离问题:节点a到b的距离为a到b路径上的节点个数
package day;
public class Demo {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int data){
this.value=data;
}
}
public static class Info{//返回值类型
public int maxDistance;
public int height;
public Info(int dis,int h){
maxDistance=dis;
height=h;
}
}
public static Info process(Node x){
//以x为头的树,最大距离分为经过x:两边树高相加再加1;不经过x:最大距离为左或右数最大距离
if(x==null){
return new Info(0,0);
}
Info left=process(x.left);
Info right=process(x.right);
int leftDis=left.maxDistance;
int rightDis=right.maxDistance;
int xDis=1+left.height+right.height;
int max=Math.max(xDis,Math.max(leftDis,rightDis));
return new Info(max,Math.max(left.height,right.height)+1);
}
public static int maxDistance(Node head){
return process(head).maxDistance;
}
}
(2)派对最大快乐值:
package day;
import java.util.*;
public class Demo {
public static class Employee{
public int happy;
public List<Employee> nexts;
}
public static class Info{//返回值类型
public int laiMaxHappy;
public int buMaxHappy;
public Info(int lai,int bu){
laiMaxHappy=lai;
buMaxHappy=bu;
}
}
public static Info process(Employee x){
if(x.nexts.isEmpty()){//基层员工
return new Info(x.happy,0);
}
int lai=x.happy;
int bu=0;
for(Employee e:x.nexts){//e为x的下层员工
Info i=process(e);
lai+=i.buMaxHappy;
bu+=i.laiMaxHappy;
}
return new Info(lai,bu);
}
public static int maxHappy(Employee boss){
Info headInfo=process(boss);
return Math.max(headInfo.laiMaxHappy,headInfo.buMaxHappy);
}
}
2、Morris遍历:(记忆)
package day;
public class Demo {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int data){
this.value=data;
}
}
public static void morris(Node head){
if(head==null){
return;
}
Node cur=head;//cur为当前节点
Node mostRight=null;//记录cur左子树最右节点
while (cur!=null){
mostRight=cur.left;
if(mostRight!=null){//cur有左子树(左孩子)
while(mostRight.right!=null && mostRight.right!=cur){
mostRight=mostRight.right;
}//循环结束,mostRight指向cur左子树最右节点
if(mostRight.right==null){//第一次来到cur节点
mostRight.right=cur;
cur=cur.left;
continue;//结束本次循环
}else {//mostRight.right==cur,第二次来到cur节点
mostRight.right=null;
}
}
cur=cur.right;
}
}
}
先序:第一次到cur时打印
package day;
public class Demo {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int data){
this.value=data;
}
}
public static void morris(Node head){
if(head==null){
return;
}
Node cur=head;//cur为当前节点
Node mostRight=null;//记录cur左子树最右节点
while (cur!=null){
mostRight=cur.left;
if(mostRight!=null){//cur有左子树(左孩子)
while(mostRight.right!=null && mostRight.right!=cur){
mostRight=mostRight.right;
}//循环结束,mostRight指向cur左子树最右节点
if(mostRight.right==null){//第一次来到cur节点
System.out.println(cur.value);
mostRight.right=cur;
cur=cur.left;
continue;//结束本次循环
}else {//mostRight.right==cur,第二次来到cur节点
mostRight.right=null;
}
}else {//cur没有左孩子,只会经过一次cur
System.out.println(cur.value);
}
cur=cur.right;
}
}
}
中序:第二次到cur时打印
package day;
public class Demo {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int data){
this.value=data;
}
}
public static void morris(Node head){
if(head==null){
return;
}
Node cur=head;//cur为当前节点
Node mostRight=null;//记录cur左子树最右节点
while (cur!=null){
mostRight=cur.left;
if(mostRight!=null){//cur有左子树(左孩子)
while(mostRight.right!=null && mostRight.right!=cur){
mostRight=mostRight.right;
}//循环结束,mostRight指向cur左子树最右节点
if(mostRight.right==null){//第一次来到cur节点
mostRight.right=cur;
cur=cur.left;
continue;//结束本次循环
}else {//mostRight.right==cur,第二次来到cur节点
mostRight.right=null;
}
}
System.out.println(cur.value);
cur=cur.right;
}
}
}
后序:比先序和中序麻烦些,有点技巧(记忆)
public class Demo {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int data){
this.value=data;
}
}
public static void morris(Node head){
if(head==null){
return;
}
Node cur=head;//cur为当前节点
Node mostRight=null;//记录cur左子树最右节点
while (cur!=null){
mostRight=cur.left;
if(mostRight!=null){//cur有左子树(左孩子)
while(mostRight.right!=null && mostRight.right!=cur){
mostRight=mostRight.right;
}//循环结束,mostRight指向cur左子树最右节点
if(mostRight.right==null){//第一次来到cur节点
mostRight.right=cur;
cur=cur.left;
continue;//结束本次循环
}else {//mostRight.right==cur,第二次来到cur节点
mostRight.right=null;
printEdge(cur.left);//逆序打印cur左孩子右边界
}
}
cur=cur.right;
}
printEdge(head);//最后单独逆序打印整棵树右边界,即根的右边界
}
public static void printEdge(Node x) {
Node tail=reverse(x);//反转链表,此时tail指向右边界最后一个节点
Node cur=tail;
while (cur!=null){
System.out.println(cur.value);
cur=cur.right;
}
reverse(tail);//反转回去
}
public static Node reverse(Node x) {
//x为当前节点
Node pre=null;//前一个节点
Node next=null;//后一个节点
while (x!=null){
next=x.right;
x.right=pre;
pre=x;
x=next;
}
return pre;
}
}
morris可以用于判断是否为搜索二叉树:(中序遍历)
public class Demo {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int data){
this.value=data;
}
}
public static boolean isBST(Node head){
if(head==null){
return true;
}
Node cur=head;//cur为当前节点
Node mostRight=null;//记录cur左子树最右节点
int preValue=Integer.MIN_VALUE;
while (cur!=null){
mostRight=cur.left;
if(mostRight!=null){//cur有左子树(左孩子)
while(mostRight.right!=null && mostRight.right!=cur){
mostRight=mostRight.right;
}//循环结束,mostRight指向cur左子树最右节点
if(mostRight.right==null){//第一次来到cur节点
mostRight.right=cur;
cur=cur.left;
continue;//结束本次循环
}else {//mostRight.right==cur,第二次来到cur节点
mostRight.right=null;
}
}
if(cur.value<=preValue){
return false;
}
cur=cur.right;
}
return true;
}
}