二叉树基本问题
二叉树的结构
二叉树的先序,中序,后序遍历
package dataClass.code02;
import java.util.Stack;
public class RecursiveTraversalBT {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int v) {
value = v;
}
}
public static void f(Node head) {
if (head == null) {
return;
}
f(head.left);
f(head.right);
}
//先序打印
public static void pre1(Node head) {
if (head == null) {
return;
}
System.out.println(head.value);
pre1(head.left);
pre1(head.right);
}
//中序打印
public static void in1(Node head) {
if (head == null) {
return;
}
in1(head.left);
System.out.println(head.value);
in1(head.right);
}
//后序打印
public static void pos1(Node head) {
if (head == null) {
return;
}
pos1(head.left);
pos1(head.right);
System.out.println(head.value);
}
//用栈实现的先序打印
public static void pre2(Node head) {
if (head != null) {
Stack<Node> stack = new Stack<>();
stack.add(head);
while (!stack.isEmpty()) {
head = stack.pop();
if (head.right != null) {
stack.push(head.right);
}
if (head.left != null) {
stack.push(head.left);
}
}
}
System.out.println();
}
//中序遍历
public static void in2(Node head) {
if (head != null) {
Stack<Node> stack = new Stack<>();
while (!stack.isEmpty() || head != null) {
if (head != null) {
stack.push(head);
head = head.left;
} else {
head = stack.pop();
System.out.println(head.value);
head = head.right;
}
}
}
System.out.println();
}
//基于特殊先序的后序遍历
public static void pos2(Node head) {
if (head != null) {
Stack<Node> s1 = new Stack<>();
Stack<Node> s2 = new Stack<>();
s1.push(head);
while (!s1.isEmpty()) {
head = s1.pop();
s2.push(head);
if (head.left != null) {
s1.push(head.left);
}
if (head.right != null) {
s1.push(head.right);
}
}
while (!s2.isEmpty()) {
System.out.println(s2.pop());
}
}
}
//只使用一个栈来进行后序遍历
public static void pos3(Node h) {
if (h != null) {
Stack<Node> stack = new Stack<>();
stack.push(h);
Node c = null;
while (!stack.isEmpty()) {
c = stack.peek();
if (c.left != null && h != c.left && h != c.right) {
stack.push(c.left);
} else if (c.right != null && h != c.right) {
stack.push(c.right);
} else {
System.out.println(stack.pop());
h = c;
}
}
}
}
}
二叉树的按层遍历
1)宽度遍历
2)发现某一层的结束(最大宽度)
public static int maxWidthUseMap(Node head){
if(head==null){
return 0;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
HashMap<Node,Integer> levelMap = new HashMap<>();
levelMap.put(head,1);
int curLevel = 1;//当前正在统计那一层
int curLevelNodes = 0;//当前正在统计那一层的宽度
int max = 0;//所有层中的最大值
while (!queue.isEmpty()){
Node cur = queue.poll();
int curNodeLevel = levelMap.get(cur);
if(cur.left!=null){
levelMap.put(cur.left,curNodeLevel+1);
queue.add(cur.left);
}
if(cur.right!=null){
levelMap.put(cur.right,curNodeLevel+1);
queue.add(cur.right);
}
if(curNodeLevel==curLevel){
curLevelNodes++;
}else {
max = Math.max(max,curLevelNodes);
curLevel++;
curLevelNodes = 1;
}
}
max = Math.max(max,curLevelNodes);
return max;
}
返回后继节点
public static Node getSuccessorNdoe(Node node) {
if (node == null) {
return node;
}
if (node.right != null) {
return getLeftMost(node.right);
} else {//无右树
Node parent = node.parent;
while (parent != null && parent.right == node) {
//当前节点是其父亲节点的右孩子
node = parent;
parent = node.parent;
}
return parent;
}
}
/**
* 找到右树上的最左节点
*
* @param node 当前节点
*/
public static Node getLeftMost(Node node) {
if (node == null) {
return node;
}
while (node.left != null) {
node = node.left;
}
return node;
}
折纸问题
public static void printAllFold(int N) {
printProcess(1, N, true);
}
/**
* 递归过程,来到了某一个节点
* @param i 节点的层数
* @param N 一共有多少层(固定)
* @param down ==true:凹 ==false:凸
*/
private static void printProcess(int i, int N, boolean down) {
if (i > N) {
return;
}
printProcess(i + 1, N, true);
System.out.println(down ? "凹" : "凸");
printProcess(i + 1, N, false);
}
public static void main(String[] args) {
int N = 3;
printAllFold(N);
}
二叉树递归套路
1)判断平衡二叉树
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static boolean isBalanced(Node head) {
return process(head).isBalaced;
}
public static class Info {
public boolean isBalaced;
public int height;
public Info(boolean b, int h) {
isBalaced = b;
height = h;
}
}
public static Info process(Node x) {
if (x == null) {
return new Info(true, 0);
}
Info leftInfo = process(x.left);
Info rightInfo = process(x.right);
//左树或者右树的高度加根节点的高度就是当前树高
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
boolean isBalaced = true;
if (!leftInfo.isBalaced || !rightInfo.isBalaced || Math.abs(leftInfo.height - rightInfo.height) > 1) {
isBalaced = false;
}
return new Info(isBalaced, height);
}
2)最大距离
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int v){
this.value = v;
}
}
public static int maxDistance(Node head){
return process(head).maxDistance;
}
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){
if(x==null){
return new Info(0,0);
}
Info leftInfo = process(x.left);
Info rightInfo = process(x.right);
int height = Math.max(leftInfo.height, rightInfo.height)+1;
int maxDistance = Math.max(Math.max(leftInfo.maxDistance, rightInfo.maxDistance), leftInfo.height+ rightInfo.height+1);
return new Info(maxDistance,height);
}
3)派对的最大快乐值
public static class Employee{
public int happy;
public List<Employee> nexts;
public Employee(int h){
happy = h;
nexts = new ArrayList<>();
}
}
public static class Info{
//头结点在来的时候整棵树的最大值
public int yes;
//头结点在不来的时候整棵树的最大值
public int no;
public Info(int y,int n){
yes = y;
no = n;
}
}
public static Info process(Employee x){
if(x.nexts.isEmpty()){
return new Info(x.happy, 0);
}
int yes = x.happy;
int no = 0;
for(Employee next : x.nexts){
Info nextInfo = process(next);
yes += nextInfo.no;
no += Math.max(nextInfo.yes, nextInfo.no);
}
return new Info(yes, no);
}
4)是否是满二叉树
public class IsFull {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int v){
this.value = v;
}
}
public static boolean isFull(Node head){
if(head == null){
return true;
}
Info all = process(head);
return (1 << all.height)-1 == all.nodes;
}
public static class Info{
public int height;
public int nodes;
public Info(int h,int n){
height = h;
nodes = n;
}
}
public static Info process(Node head){
if(head == null){
return new Info(0,0);
}
Info leftInfo = process(head.left);
Info rightInfo = process(head.right);
int height = Math.max(leftInfo.height, rightInfo.height)+1;
int nodes = leftInfo.nodes+rightInfo.nodes+1;
return new Info(height,nodes);
}
}
5)判断是否为完全二叉树
思路:
- 任何节点有右孩子而没有左孩子,直接返回false,否则继续
- 一但遇到左右孩子不双全,后续所遇到的节点必须全部为叶节点
public class IsCBT {
public static class Node {
public int value;
public IsCBT.Node left;
public IsCBT.Node right;
public Node(int v) {
this.value = v;
}
}
public static boolean isBCT1(Node head) {
if (head == null) {
return true;
}
//宽度优先遍历使用队列
LinkedList<Node> queue = new LinkedList<>();
//是否遇到过左右孩子不双全的节点
boolean leaf = false;
Node l = null;
Node r = null;
queue.add(head);
while (!queue.isEmpty()) {
head = queue.poll();
l = head.left;
r = head.right;
//如果遇到了不不双全的节点,又发现当前节点不是叶节点
if ((leaf && !(l == null && r == null)) || (l == null && r != null)) {
return false;
}
if (l != null) {
queue.add(l);
}
if (r != null) {
queue.add(r);
}
if (l == null || r == null) {
leaf = true;
}
}
return true;
}
/*
递归套路
1)左边是满二叉树,右边是满二叉树,左右高度一样
2)左边是满二叉树,右边是满二叉树,左比右高一
3)左边是完全二叉树,右边是满二叉树,左比右高一
4)左边是满二叉树,右边是完全二叉树,左右高度相等
*/
public static boolean isCBT2(Node head) {
if (head == null) {
return true;
}
return process(head).isCBT;
}
//对于每一颗子树,是否是满二叉树,是否是完全二叉树,高度
public static class Info {
public boolean isFull;
public boolean isCBT;
public int height;
public Info(boolean full, boolean cbt, int h) {
isFull = full;
isCBT = cbt;
height = h;
}
}
public static Info process(Node x) {
if (x == null) {
return new Info(true, true, 0);
}
Info leftInfo = process(x.left);
Info rightInfo = process(x.right);
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
boolean isFull = leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height;
boolean isCBT = false;
if (isFull) {
isCBT = true;
} else {
if (leftInfo.isCBT && leftInfo.isCBT) {
if (leftInfo.isCBT && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) {
isCBT = true;
}
if (leftInfo.isFull && rightInfo.isFull && leftInfo.height == rightInfo.height + 1) {
isCBT = true;
}
if (leftInfo.isFull && rightInfo.isCBT && leftInfo.height == rightInfo.height) {
isCBT = true;
}
}
}
return new Info(isFull, isCBT, height);
}
}
6)最低公共祖先问题
package dataClass.code02;
import java.util.HashMap;
import java.util.HashSet;
public class lowestAncestor {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int v){
this.value = v;
}
}
public static Node lowestAncestor1(Node head,Node o1,Node o2){
if(head == null){
return null;
}
//key的父节点是value
HashMap<Node,Node> parentMap = new HashMap<>();
parentMap.put(head, null);
fillParentMap(head,parentMap);
HashSet<Node> o1Set = new HashSet<>();
Node cur = o1;
o1Set.add(cur);
while (parentMap.get(cur)!=null){
cur = parentMap.get(cur);
o1Set.add(cur);
}
cur = o2;
while (!o1Set.contains(cur)){
cur = parentMap.get(cur);
}
return cur;
}
public static void fillParentMap(Node head,HashMap<Node,Node> parentMap){
if(head.left!=null){
parentMap.put(head.left,head);
//递归填写左树的所有节点
fillParentMap(head.left,parentMap);
}
if(head.right!=null){
parentMap.put(head.right,head);
//递归填写右树的所有节点
fillParentMap(head.right,parentMap);
}
}
/*
递归套路
1) o1,o2没有一个在x上
2) o1,o2只有一个在x上
3) o1,o2都在x为头结点的树上
1.左右各有一个
2.左子树包含所有的o1,o2
3.右子树包含所有的o1,o2
4.o1,o2有一个在头结点上,另一个在子树中
*/
//任何子树返回三个信息,最初的交汇点,是否发现o1,是否发现o2
public static class Info{
public Node ans;
public boolean findO1;
public boolean findO2;
public Info(Node a,boolean f1,boolean f2){
ans = a;
findO1 = f1;
findO2 = f2;
}
}
public static Info process(Node x,Node o1,Node o2){
if(x == null){
return new Info(null,false,false);
}
Info leftInfo = process(x.left,o1,o2);
Info rightInfo = process(x.right,o1,o2);
boolean findO1 = x == o1 || leftInfo.findO1 || rightInfo.findO1;
boolean findO2 = x == o2 || leftInfo.findO2 || rightInfo.findO2;
//o1和o2最初的交汇点
Node ans = null;
if(leftInfo.ans!=null){
ans = leftInfo.ans;
}
if(rightInfo.ans!=null){
ans = rightInfo.ans;
}
if(ans == null){
if(findO1 && findO2){
ans = x;
}
}
return new Info(ans,findO1,findO2);
}
}