二叉树的递归套路
判断是否是搜索二叉树
什么是二叉搜索树?
二叉搜索树或者是一棵空树亦或者是满足以下条件的二叉树:
(1)每个结点都有一个作为搜索依据的关键码(key),所有结点的关键码互不相同。
(2)左子树(如果存在)上的所有结点的关键码都小于根结点的关键码。
(3)右子树(如果存在)上的所有结点的关键码都大于根结点的关键码。
(4)左子树和右子树也是二叉搜索树。
import java.util.ArrayList;
public class IsBST {
//判断二叉树是否是搜索二叉树
//(1)每个结点都有一个作为搜索依据的关键码(key),所有结点的关键码互不相同。
// (2)左子树(如果存在)上的所有结点的关键码都小于根结点的关键码。
// (3)右子树(如果存在)上的所有结点的关键码都大于根结点的关键码。
// (4)左子树和右子树也是二叉搜索树。
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int value){
this.value= value;
}
}
public static boolean isBST1(Node head){
if (head == null){
return true;
}
ArrayList<Node> list = new ArrayList<>();
in(head,list);
for (int i = 1; i < list.size(); i++) {
if (list.get(i).value <= list.get(i-1).value){
return false;
}
}
return true;
}
private static void in(Node head, ArrayList<Node> list) {
if (head == null){
return;
}
in(head.left,list);
list.add(head);
in(head.right,list);
}
public static boolean isBST2(Node head){
if (head == null){
return true;
}
return process(head).isBST;
}
public static class Info{
public boolean isBST; //是否是搜索二叉树
public int max; //最大值
public int min; //最小值
public Info(boolean isBST, int max, int min) {
this.isBST = isBST;
this.max = max;
this.min = min;
}
}
public static Info process(Node x){
if (x == null){
return null;
}
Info leftInfo = process(x.left);
Info rightInfo = process(x.right);
int max =x.value;
if (leftInfo != null){
max = Math.max(max,leftInfo.max);
}
if (rightInfo != null){
max = Math.max(max,rightInfo.max);
}
int min =x.value;
if (leftInfo != null){
min = Math.min(min,leftInfo.min);
}
if (rightInfo != null){
min = Math.min(min,rightInfo.min);
}
boolean isBST = true;
if (leftInfo != null && !leftInfo.isBST){
isBST = false;
}
if (rightInfo != null && !rightInfo.isBST){
isBST = false;
}
if (leftInfo != null && x.value <= leftInfo.max){
isBST = false;
}
if (rightInfo != null && x.value >= rightInfo.min){
isBST = false;
}
return new Info(isBST,max,min);
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
public static void main(String[] args) {
int maxLevel = 4;
int maxValue = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
if (isBST1(head) != isBST2(head)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
}
判断是否是完全二叉树
判断一棵树是否是完全二叉树的思路:
1>如果树为空,则直接返回错。
2>如果树不为空:层序遍历二叉树。
2.1>如果一个结点左右孩子都不为空,则pop该节点,将其左右孩子入队列。
2.2>如果遇到一个结点,左孩子为空,右孩子不为空,则该树一定不是完全二叉树。
import java.util.LinkedList;
import java.util.Queue;
public class IsCBT {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int value){
this.value = value;
}
}
//判断是否为完全二叉树
//如果一棵具有n个结点的深度为k的二叉树,它的每一个结点都与深度为k的满二叉树中编号为1~n的结点一一对应,这棵二叉树称为完全二叉树。
public static boolean isCBT1(Node head){
if (head == null){
return true;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
Node r = null;
Node l = null;
boolean leaf = false; //判断是否为叶子节点
while (!queue.isEmpty()){
Node cur = queue.poll();
l = cur.left;
r = cur.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;
}
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 isFull, boolean isCBT, int height) {
this.isFull = isFull;
this.isCBT = isCBT;
this.height = height;
}
}
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 { //以x为整棵树、不满
if (leftInfo.isCBT && rightInfo.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);
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
public static void main(String[] args) {
int maxLevel = 5;
int maxValue = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
if (isCBT1(head) != isCBT2(head)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
}
判断是否是平衡二叉树
平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
public class IsBalanced {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int value){
this.value = value;
}
}
//给定一棵二叉树的头节点head,返回这颗二叉树是不是平衡二叉树
public static boolean isBalanced1(Node head){
boolean[] ans = new boolean[1];
ans[0] = true;
process1(head,ans);
return ans[0];
}
private static int process1(Node head, boolean[] ans) {
if (head == null || !ans[0]){
return -1;
}
int leftHeight = process1(head.left,ans);
int rightHeight = process1(head.right,ans);
if (Math.abs(leftHeight-rightHeight) >1){
ans[0] = false;
}
return Math.max(leftHeight,rightHeight)+1;
}
public static boolean isBalanced2(Node head){
return process2(head).isBalanced;
}
public static class Info{
public boolean isBalanced;
public int height;
public Info(boolean isBalanced, int height) {
this.isBalanced = isBalanced;
this.height = height;
}
}
public static Info process2(Node x){
if (x == null){
return new Info(true,0);
}
Info leftInfo = process2(x.left);
Info rightInfo = process2(x.right);
boolean isBalanced = true;
int height = Math.max(leftInfo.height,rightInfo.height)+1;
if (!leftInfo.isBalanced || !rightInfo.isBalanced){
isBalanced = false;
}
if (Math.abs(leftInfo.height-rightInfo.height)>1){
isBalanced = false;
}
return new Info(isBalanced,height);
}
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
public static void main(String[] args) {
int maxLevel = 5;
int maxValue = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
if (isBalanced1(head) != isBalanced2(head)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
}
判断是否是满二叉树
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。
public class IsFull {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int value) {
this.value = value;
}
}
//给定一棵二叉树的头节点head,返回这颗二叉树是不是满二叉树
public static boolean isFull1(Node head){
if (head == null){
return true;
}
int height = h(head); //二叉树层数
int nodes = n(head); //二叉树的节点数
//是满二叉树的条件:2^k - 1 = n k是树的高度,n是树的节点数
return (1 << height) -1 == nodes;
}
private static int n(Node head) {
if (head == null){
return 0;
}
return n(head.left)+n(head.right)+1;
}
private static int h(Node head) {
if (head == null){
return 0;
}
return Math.max(h(head.left),h(head.right))+1;
}
public static boolean isFull2(Node head){
if (head == null){
return true;
}
return process(head).isFull;
}
public static class Info{
public boolean isFull;
public int height;
public int n;
public Info(boolean isFull, int height, int n) {
this.isFull = isFull;
this.height = height;
this.n = n;
}
}
public static Info process(Node head){
if (head == null){
return new Info(true,0,0);
}
boolean isFull = true;
Info leftInfo = process(head.left);
Info rightInfo = process(head.right);
int height = Math.max(leftInfo.height,rightInfo.height)+1;
int n = leftInfo.n + rightInfo.n +1;
if (!leftInfo.isFull || !rightInfo.isFull){
isFull = false;
}
if ((1<<height) -1 != n){
isFull = false;
}
return new Info(isFull,height,n);
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
public static void main(String[] args) {
int maxLevel = 5;
int maxValue = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
if (isFull1(head) != isFull2(head)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
}
求二叉树最大二叉搜索子树的大小
import java.util.ArrayList;
public class MaxSubBSTSize {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int value) {
this.value = value;
}
}
//给定一棵二叉树的头节点head,
//返回这颗二叉树中最大的二叉搜索子树的大小
public static int getBSTSize(Node head){
if (head == null){
return 0;
}
ArrayList<Node> list = new ArrayList<>();
in(head,list);
for (int i = 1; i < list.size(); i++) {
if (list.get(i).value <= list.get(i-1).value){
return 0;
}
}
return list.size();
}
private static void in(Node head, ArrayList<Node> list) {
if (head == null){
return;
}
in(head.left,list);
list.add(head);
in(head.right,list);
}
public static int maxSubBSTSize1(Node head){
if (head == null){
return 0;
}
int h = getBSTSize(head);
if (h != 0){
return h;
}
return Math.max(maxSubBSTSize1(head.left),maxSubBSTSize1(head.right));
}
public static int maxSubBSTSize2(Node head){
if (head == null){
return 0;
}
return process(head).maxBSTSubtreeSize;
}
public static class Info{
public int maxBSTSubtreeSize;
public int allSize;
public int max;
public int min;
public Info(int maxBSTSubtreeSize, int allSize, int max, int min) {
this.maxBSTSubtreeSize = maxBSTSubtreeSize;
this.allSize = allSize;
this.max = max;
this.min = min;
}
}
public static Info process(Node x){
if (x == null){
return null;
}
Info leftInfo = process(x.left);
Info rightInfo = process(x.right);
int allSize = 1;
int max = x.value;
int min = x.value;
if (leftInfo != null){
max = Math.max(max,leftInfo.max);
min = Math.min(min,leftInfo.min);
allSize +=leftInfo.allSize;
}
if (rightInfo != null){
max = Math.max(max,rightInfo.max);
min = Math.min(min,rightInfo.min);
allSize +=rightInfo.allSize;
}
int p1=-1;
if (leftInfo != null){
p1 = leftInfo.maxBSTSubtreeSize;
}
int p2 = -1;
if (rightInfo != null){
p2 = rightInfo.maxBSTSubtreeSize;
}
int p3 = -1;
boolean leftBST = leftInfo == null ? true : (leftInfo.maxBSTSubtreeSize == leftInfo.allSize);
boolean rightBST = rightInfo == null ? true : (rightInfo.maxBSTSubtreeSize == rightInfo.allSize);
if (leftBST && rightBST){
boolean leftMaxLessX = leftInfo == null ? true : (leftInfo.max < x.value);
boolean rightMinMoreX = rightInfo == null ? true : (rightInfo.min > x.value);
if (leftMaxLessX && rightMinMoreX){
int leftSize = leftInfo == null ? 0 : leftInfo.allSize;
int rightSize = rightInfo == null ? 0 : rightInfo.allSize;
p3 = leftSize + rightSize + 1;
}
}
return new Info(Math.max(p1,Math.max(p2,p3)),allSize,max,min);
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
public static void main(String[] args) {
int maxLevel = 4;
int maxValue = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
if (maxSubBSTSize1(head) != maxSubBSTSize2(head)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
}
求一棵二叉树中两个节点间的最大距离
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
public class MaxDistance {
//给定一棵二叉树的头节点head,任何两个节点之间都存在距离,
//返回整棵二叉树的最大距离
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int value){
this.value = value;
}
}
public static int maxDistance1(Node head){
if (head == null){
return 0;
}
ArrayList<Node> arr = getPreList(head);
HashMap<Node,Node> parentMap = getParentMap(head);
int max = 0;
for (int i = 0; i < arr.size(); i++) {
for (int j = i; j < arr.size(); j++) {
max = Math.max(max, distance(parentMap, arr.get(i), arr.get(j)));
}
}
return max;
}
private static int distance(HashMap<Node, Node> parentMap, Node o1, Node o2) {
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);
}
Node lowestAncestor = cur;
cur = o1;
int distance1 = 1;
while (cur != lowestAncestor){
cur = parentMap.get(cur);
distance1++;
}
cur = o2;
int distance2 = 1;
while (cur != lowestAncestor){
cur = parentMap.get(cur);
distance2++;
}
return distance1+distance2-1;
}
private static HashMap<Node, Node> getParentMap(Node head) {
HashMap<Node,Node> map = new HashMap<>();
map.put(head,null);
fileParentMap(head,map);
return map;
}
private static void fileParentMap(Node head, HashMap<Node, Node> map) {
if (head == null){
return;
}
if (head.left != null){
map.put(head.left,head);
fileParentMap(head.left,map);
}
if (head.right != null){
map.put(head.right,head);
fileParentMap(head.right,map);
}
}
private static ArrayList<Node> getPreList(Node head) {
ArrayList<Node> arr = new ArrayList<>();
filePreList(head,arr);
return arr;
}
private static void filePreList(Node head, ArrayList<Node> arr) {
if (head == null){
return;
}
arr.add(head);
filePreList(head.left,arr);
filePreList(head.right,arr);
}
public static int maxDistance2(Node head){
if (head == null){
return 0;
}
return process(head).maxDistance;
}
public static class Info{
public int maxDistance;
public int height;
public Info(int maxDistance, int height) {
this.maxDistance = maxDistance;
this.height = height;
}
}
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 d1 = leftInfo.maxDistance;
int d2 = rightInfo.maxDistance;
int d3 = leftInfo.height+ rightInfo.height + 1;
int maxDistance = Math.max(Math.max(d1,d2),d3);
return new Info(maxDistance,height);
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
public static void main(String[] args) {
int maxLevel = 4;
int maxValue = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
if (maxDistance1(head) != maxDistance2(head)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
}
求二叉树中两个节点的最低公共祖先
import java.util.ArrayList;
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 value){
this.value = value;
}
}
//给定一棵二叉树的头节点head,和另外两个节点a和b。
//返回a和b的最低公共祖先
public static Node lowestAncestor1(Node head,Node o1,Node o2){
if (head == null){
return null;
}
HashMap<Node,Node> parentMap = new HashMap<>();
parentMap.put(head,null);
fillParentMap(head,parentMap);
HashSet<Node> o1Set = new HashSet<>();
Node cur = o1;
o1Set.add(cur);
//找到o1节点的上游的节点、放在hashset里
while (parentMap.get(cur) != null){
cur = parentMap.get(cur);
o1Set.add(cur);
}
cur = o2;
//将o2和o2的上游节点逐个与o1所有父节点相比,如果相等则是最低父节点,
while (!o1Set.contains(cur)){
cur = parentMap.get(cur);
}
return cur;
}
//存放一个节点对应的父节点map
public static void fillParentMap(Node head,HashMap<Node,Node> parentMap){
if (head == null){
return;
}
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);
}
}
public static Node lowestAncestor2(Node head,Node o1,Node o2){
if (head == null){
return null;
}
return process(head,o1,o2).ans;
}
public static class Info{
public boolean findO1;
public boolean findO2;
public Node ans;
public Info(boolean findO1, boolean findO2, Node ans) {
this.findO1 = findO1;
this.findO2 = findO2;
this.ans = ans;
}
}
public static Info process(Node x,Node o1,Node o2){
if (x == null){
return new Info(false,false,null);
}
Info leftInfo = process(x.left,o1,o2);
Info rightInfo = process(x.right,o1,o2);
Node ans = null;
boolean findO1 = leftInfo.findO1 || rightInfo.findO1 || (x == o1);
boolean findO2 = leftInfo.findO2 || rightInfo.findO2 || (x == o2);
if (leftInfo.ans != null && leftInfo.findO1 && leftInfo.findO2){
ans = leftInfo.ans;
}
if (rightInfo.ans != null && rightInfo.findO1 && rightInfo.findO2){
ans = rightInfo.ans;
}
if (findO1 && findO2 && leftInfo.ans == null && rightInfo.ans == null){
ans = x;
}
return new Info(findO1,findO2,ans);
}
// for test
public static Node generateRandomBST(int maxLevel, int maxValue) {
return generate(1, maxLevel, maxValue);
}
// for test
public static Node generate(int level, int maxLevel, int maxValue) {
if (level > maxLevel || Math.random() < 0.5) {
return null;
}
Node head = new Node((int) (Math.random() * maxValue));
head.left = generate(level + 1, maxLevel, maxValue);
head.right = generate(level + 1, maxLevel, maxValue);
return head;
}
// for test
public static Node pickRandomOne(Node head) {
if (head == null) {
return null;
}
ArrayList<Node> arr = new ArrayList<>();
fillPrelist(head, arr);
int randomIndex = (int) (Math.random() * arr.size());
return arr.get(randomIndex);
}
// for test
public static void fillPrelist(Node head, ArrayList<Node> arr) {
if (head == null) {
return;
}
arr.add(head);
fillPrelist(head.left, arr);
fillPrelist(head.right, arr);
}
public static void main(String[] args) {
int maxLevel = 4;
int maxValue = 100;
int testTimes = 1000000;
for (int i = 0; i < testTimes; i++) {
Node head = generateRandomBST(maxLevel, maxValue);
Node o1 = pickRandomOne(head);
Node o2 = pickRandomOne(head);
if (lowestAncestor1(head, o1, o2) != lowestAncestor2(head, o1, o2)) {
System.out.println("Oops!");
}
}
System.out.println("finish!");
}
}
----from 左程云算法基础课