8.二叉树的递归套路

二叉树的递归套路
  • 可以解决面试中绝大多数(95%)的二叉树问题尤其是树型dp问题
  • 本质是利用递归遍历二叉树的便利性

小技巧多如牛毛,大技巧就两个:二叉树的递归套路、暴力递归改动态规划的套路

所谓二叉树的递归套路就是在树上做动态规划,什么是动态规划呢?动态规划就是用时间换空间的方式。

二叉树的递归套路

1)假设以X节点为头,假设可以向X左树和X右树要任何信息
2)在上一步的假设下,讨论以X为头节点的树,得到答案的可能性(最重要)
3)列出所有可能性后,确定到底需要向左树和右树要什么样的信息
4)把左树信息和右树信息求全集,就是任何一棵子树都需要返回的信息S
5)递归函数都返回S,每一棵子树都这么要求
6)写代码,在代码中考虑如何把左树的信息和右树信息整合出整棵树的信息

二叉树的递归套路深度实践
【题目1】

给定一颗二叉树的头节点head,返回这颗二叉树是不是平衡二叉树

什么是平衡树:在一棵二叉树中,每一颗子树左树的高度与右树的高度差不超过1

此题满足条件:

  • 1)左树平衡
  • 2)右树平衡
  • 3)左树与右树高度差不超过1
package com.harrison.class08;

public class Code01_IsBalanced {
    
    
	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 boolean isBalanced;
		public int height;

		public Info(boolean i, int h) {
    
    
			isBalanced = i;
			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 isBalanced = true;
		if (!leftInfo.isBalanced) {
    
    
			isBalanced = false;
		}
		if (!rightInfo.isBalanced) {
    
    
			isBalanced = false;
		}
		if (Math.abs(leftInfo.height - rightInfo.height) > 1) {
    
    
			isBalanced = false;
		}
		return new Info(isBalanced, height);
	}

	public static boolean isBalanced2(Node head) {
    
    
		return process(head).isBalanced;
	}

	public static int process1(Node head, boolean[] ans) {
    
    
		if (!ans[0] || head == null) {
    
    
			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 isBalanced1(Node head) {
    
    
		boolean[] ans = new boolean[1];
		ans[0] = true;
		process1(head, ans);
		return ans[0];
	}

	// 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 (isBalanced1(head) != isBalanced2(head)) {
    
    
				System.out.println("Oops!");
			}
		}
		System.out.println("finish!");
	}
}
【题目2】

给定一颗二叉树的头结点head,任何两个结点之间都存在距离,返回整颗二叉树的最大距离

package com.harrison.class08;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

public class Code02_MaxDistance {
    
    
	public static class Node {
    
    
		public int value;
		public Node left;
		public Node right;

		public Node(int data) {
    
    
			this.value = data;
		}
	}

	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;
	}

	public static ArrayList<Node> getPrelist(Node head) {
    
    
		ArrayList<Node> arr = new ArrayList<>();
		fillPrelist(head, arr);
		return arr;
	}

	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 HashMap<Node, Node> getParentMap(Node head) {
    
    
		HashMap<Node, Node> map = new HashMap<>();
		map.put(head, null);
		fillParentMap(head, map);
		return map;
	}

	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);
		}
	}

	public 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;
	}

//	public static class Info {
    
    
//		public int maxDistance;
//		public int height;
//
//		public Info(int m, int h) {
    
    
//			maxDistance=m;
//			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);
//	}
//	
//	public static int maxDistance2(Node head) {
    
    
//		return process(head).maxDistance;
//	}

	public static int maxDistance2(Node head) {
    
    
		return process(head).maxDistance;
	}

	public static class Info {
    
    
		public int maxDistance;
		public int height;

		public Info(int m, int h) {
    
    
			maxDistance = m;
			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 p1 = leftInfo.maxDistance;
		int p2 = rightInfo.maxDistance;
		int p3 = leftInfo.height + rightInfo.height + 1;
		int maxDistance = Math.max(Math.max(p1, p2), p3);
		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!");
	}
}
【题目3】

给定一颗二叉树的头结点head,返回这颗二叉树中最大的二叉搜索子树的头结点

搜索二叉树定义:左树比头结点小,右树比头结点大,每颗子树都如此

package com.harrison.class08;

import java.util.ArrayList;

public class Code03_MaxSubBSTSize {
    
    
	public static class Node {
    
    
		public int value;
		public Node left;
		public Node right;

		public Node(int data) {
    
    
			this.value = data;
		}
	}

	public static int getBSTSize(Node head) {
    
    
		if (head == null) {
    
    
			return 0;
		}
		ArrayList<Node> arr = new ArrayList<>();
		in(head, arr);
		for (int i = 1; i < arr.size(); i++) {
    
    
			if (arr.get(i).value <= arr.get(i - 1).value) {
    
    
				return 0;
			}
		}
		return arr.size();
	}

	public static void in(Node head, ArrayList<Node> arr) {
    
    
		if (head == null) {
    
    
			return;
		}
		in(head.left, arr);
		arr.add(head);
		in(head.right, arr);
	}

	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 class Info{
    
    
//		public boolean isAllBST;
//		public int maxSubBSTSize;
//		public int min;
//		public int max;
//		
//		public Info(boolean is,int size,int mi,int ma) {
    
    
//			isAllBST=is;
//			maxSubBSTSize=size;
//			min=mi;
//			max=ma;
//		}
//	}
//
//	public static Info process(Node x) {
    
    
//		if(x==null) {
    
    
//			return null;
//		}
//		Info leftInfo=process(x.left);
//		Info rightInfo=process(x.right);
//		
//		int min=x.value;
//		int max=x.value;
//		
//		if(leftInfo!=null) {
    
    
//			min=Math.min(min, leftInfo.min);
//			max=Math.max(max, leftInfo.max);
//		}
//		if(rightInfo!=null) {
    
    
//			min=Math.min(min, rightInfo.min);
//			max=Math.max(max, rightInfo.max);
//		}
//		
//		
//		int maxSubBSTSize=0;
//		if(leftInfo!=null) {
    
    
//			maxSubBSTSize=leftInfo.maxSubBSTSize;
//		}
//		if(rightInfo!=null) {
    
    
//			maxSubBSTSize=Math.max(maxSubBSTSize, rightInfo.maxSubBSTSize);
//		}
//		boolean isAllBST=false;
//		
//		if(
//			//左树整体需要是搜索二叉树
//			(leftInfo==null?true:leftInfo.isAllBST)
//			&&
//			//右树整体需要是搜索二叉树
//			(rightInfo==null?true:rightInfo.isAllBST)
//			&&
//			//左树最大值<x
//			(leftInfo==null?true:leftInfo.max<x.value)
//			&&
//			//右树最小值>x
//			(rightInfo==null?true:rightInfo.min>x.value)
//		) {
    
    
//			maxSubBSTSize=
//					(leftInfo==null?0:leftInfo.maxSubBSTSize)
//					+
//					(rightInfo==null?0:rightInfo.maxSubBSTSize)
//					+
//					1;
//				isAllBST=true;
//					
//		}
//		return new Info(isAllBST,maxSubBSTSize,min,max);
//	}
//	
//	public static int maxSubBSTSize2(Node head) {
    
    
//		if(head==null) {
    
    
//			return 0;
//		}
//		return process(head).maxSubBSTSize;
//	}

	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 m, int a, int ma, int mi) {
    
    
			maxBSTSubtreeSize = m;
			allSize = a;
			max = ma;
			min = mi;
		}
	}

	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;
		int min = x.value;
		int allSize = 1;
		if (leftInfo != null) {
    
    
			max = Math.max(leftInfo.max, max);
			min = Math.min(leftInfo.min, min);
			allSize += leftInfo.allSize;
		}
		if (rightInfo != null) {
    
    
			max = Math.max(rightInfo.max, max);
			min = Math.min(rightInfo.min, 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 : (x.value < rightInfo.min);
			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!");
	}

}
【题目4】

派对的最大快乐值

员工信息的定义如下:

class Employee{
    
    
	public int happy;//这名员工可以带来的快乐值
	List<Employee> subordinates;//这名员工有哪些直接下级
}

派对的最大快乐值:
公司的每个员工都符合Employee类的描述。整个公司的人员结构可以看作是一棵标准的、没有环的多叉树。树的头节点是公司唯一的老板。除老板之外的每个员工都有唯一的直接上级。叶节点是没有任何下属的基层员工(subordinates列表为空),除基层员工外,每个员工都有一一个或多个直接下级。

package com.harrison.class08;

import java.util.ArrayList;
import java.util.List;

public class Code04_MaxHappy {
    
    
	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 no;
		public int yes;

		public Info(int n, int y) {
    
    
			no = n;
			yes = y;
		}
	}

	public static Info process(Employee x) {
    
    
		if (x == null) {
    
    
			return new Info(0, 0);
		}
		int no = 0;
		int yes = x.happy;
		for (Employee next : x.nexts) {
    
    
			Info nextInfo = process(next);
			no += Math.max(nextInfo.no, nextInfo.yes);
			yes += nextInfo.no;
		}
		return new Info(no, yes);
	}

	public static int maxHappy1(Employee boss) {
    
    
		if (boss == null) {
    
    
			return 0;
		}
		return process1(boss, false);
	}

	// 当前来到的节点叫cur,
	// up表示cur的上级是否来,
	// 该函数含义:
	// 如果up为true,表示在cur上级已经确定来,的情况下,cur整棵树能够提供最大的快乐值是多少?
	// 如果up为false,表示在cur上级已经确定不来,的情况下,cur整棵树能够提供最大的快乐值是多少?
	public static int process1(Employee cur, boolean up) {
    
    
		if (up) {
    
     // 如果cur的上级来的话,cur没得选,只能不来
			int ans = 0;
			for (Employee next : cur.nexts) {
    
    
				ans += process1(next, false);
			}
			return ans;
		} else {
    
     // 如果cur的上级不来的话,cur可以选,可以来也可以不来
			int p1 = cur.happy;
			int p2 = 0;
			for (Employee next : cur.nexts) {
    
    
				p1 += process1(next, true);
				p2 += process1(next, false);
			}
			return Math.max(p1, p2);
		}
	}

	public static int maxHappy2(Employee head) {
    
    
		Info allInfo = process(head);
		return Math.max(allInfo.no, allInfo.yes);
	}

	public static Employee genarateBoss(int maxLevel, int maxNexts, int maxHappy) {
    
    
		if (Math.random() < 0.02) {
    
    
			return null;
		}
		Employee boss = new Employee((int) (Math.random() * (maxHappy + 1)));
		genarateNexts(boss, 1, maxLevel, maxNexts, maxHappy);
		return boss;
	}

	// for test
	public static void genarateNexts(Employee e, int level, int maxLevel, int maxNexts, int maxHappy) {
    
    
		if (level > maxLevel) {
    
    
			return;
		}
		int nextsSize = (int) (Math.random() * (maxNexts + 1));
		for (int i = 0; i < nextsSize; i++) {
    
    
			Employee next = new Employee((int) (Math.random() * (maxHappy + 1)));
			e.nexts.add(next);
			genarateNexts(next, level + 1, maxLevel, maxNexts, maxHappy);
		}
	}

	public static void main(String[] args) {
    
    
		int maxLevel = 4;
		int maxNexts = 7;
		int maxHappy = 100;
		int testTimes = 100000;
		for (int i = 0; i < testTimes; i++) {
    
    
			Employee boss = genarateBoss(maxLevel, maxNexts, maxHappy);
			if (maxHappy1(boss) != maxHappy2(boss)) {
    
    
				System.out.println("Oops!");
			}
		}
		System.out.println("finish!");
	}

}
【题目5】

给定一棵二叉树的头节点head,返回这颗二叉树是不是满二叉树

package com.harrison.class08;

public class Code05_IsFull {
    
    
	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 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);
	}

	public static boolean isFull1(Node head) {
    
    
		if (head == null) {
    
    
			return true;
		}
		int height = h(head);
		int nodes = n(head);
		return (1 << height) - 1 == nodes;
	}

	public static int h(Node head) {
    
    
		if (head == null) {
    
    
			return 0;
		}
		return Math.max(h(head.left), h(head.right)) + 1;
	}

	public static int n(Node head) {
    
    
		if (head == null) {
    
    
			return 0;
		}
		return n(head.left) + n(head.right) + 1;
	}

	public static boolean isFull2(Node head) {
    
    
		if (head == null) {
    
    
			return true;
		}
		Info all = process(head);
		return (1 << all.height) - 1 == all.nodes;
	}

	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!");
	}
}
【题目6】

给定一棵二叉树的头节点head,返回这颗二叉树中是不是完全二叉树

列可能性:如果四种情况都不符合,必不是完全二叉树,如果有一种情况成立,就是

  • 1)满二叉树(无缺口)
  • 2)左树是完全二叉树,右树是满二叉树,并且左树高度比右树高度大1
  • 3)左树是满二叉树,右树是满二叉树,且左树高度比右树高度大1
  • 4)左树是满二叉树,右树是完全二叉树,且两边高度一样
package com.harrison.class08;

import java.util.LinkedList;

public class Code06_IsCBT {
    
    
	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 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 {
    
    // 以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);
	}

	public static boolean isCBT1(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;
	}

	public static boolean isCBT2(Node head) {
    
    
		if (head == null) {
    
    
			return true;
		}
		return process(head).isCBT;
	}

	// 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!");
	}
}
【题目7】

给定一棵二叉树的头节点head,和另外两个节点a和b。返回a和b的最低公共祖先

最低公共祖先:a和b往上走初次交汇的点

  • 1)o1和o2都不在x上
  • 2)o1和o2只有一个在x上
  • 3)o1和o2都在以x为头结点的树上
    • 1> 左树右树各一个
    • 2> 左树有两个
    • 3> 右树有两个
    • 4> x自己是o1或o2

左树右树各返回三个信息:

  • 1)o1和o2最初交汇点,没有交汇点返回null
  • 2)在子树上是否发现o1
  • 3)在子树上是否发现o2
package com.harrison.class08;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

public class Code07_LowestAncestor {
    
    
	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 Node ans;
		public boolean findA;
		public boolean findB;

		public Info(Node an, boolean fA, boolean fB) {
    
    
			ans = an;
			findA = fA;
			findB = fB;
		}
	}

	public static Info process(Node x, Node a, Node b) {
    
    
		if (x == null) {
    
    
			return new Info(null, false, false);
		}
		Info leftInfo = process(x.left, a, b);
		Info rightInfo = process(x.right, a, b);
		boolean findA = (x == a) || leftInfo.findA || rightInfo.findA;
		boolean findB = (x == b) || leftInfo.findB || rightInfo.findB;
		Node ans = null;
		if (leftInfo.ans != null) {
    
    
			ans = leftInfo.ans;
		} else if (rightInfo.ans != null) {
    
    
			ans = rightInfo.ans;
		} else {
    
    
			if (findA && findB) {
    
    
				ans = x;
			}
		}
		return new Info(ans, findA, findB);
	}

	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);
		}
	}

	public static Node lowestAncestor2(Node head, Node a, Node b) {
    
    
		return process(head, a, b).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!");
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_44337241/article/details/121202981