算法基础08-二叉树的递归思维

1 二叉树的递归套路

1、 可以解决面试中的绝大部分二叉树(95%以上)的问题,尤其是树形dp问题

2、 其本质是利用递归遍历二叉树的便利性,每个节点在递归的过程中可以回到该节点3次

具体步骤为:

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

1.1 二叉树的递归套路深度实践

1.1.1 例一:判断二叉树平衡与否

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

平衡树概念:在一棵二叉树中,每一个子树,左树的高度和右树的高度差不超过1

那么如果以X为头的这颗树,要做到平衡,那么X的左树要是平衡的,右树也是平衡的,且X的左树高度和右树高度差不超过1

所以该题,我们X需要向左右子树要的信息为,1.高度 2. 是否平衡

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

	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 isBalanced2(Node head) {
		return process2(head).isBalaced;
	}

	// 左、右要求一样,Info 表示信息返回的结构体
	public static class Info {
	        // 是否平衡
		public boolean isBalaced;
		// 高度多少
		public int height;

		public Info(boolean b, int h) {
			isBalaced = b;
			height = h;
		}
	}

        // 递归调用,X自身也要返回信息Info。
        // 解决X节点(当前节点)怎么返回Info信息
	public static Info process2(Node X) {
	        // base case
		if (X == null) {
			return new Info(true, 0);
		}
		// 得到左树信息
		Info leftInfo = process2(X.left);
		// 得到右树信息
		Info rightInfo = process2(X.right);
		
		// 高度等于左右最大高度,加上当前头结点的高度1
		int height = Math.max(leftInfo.height, rightInfo.height) + 1;
		boolean isBalanced = true;
		// 左树不平衡或者右树不平衡,或者左右两子树高度差超过1
		// 那么当前节点为头的树,不平衡
		if (!leftInfo.isBalaced || !rightInfo.isBalaced || Math.abs(leftInfo.height - rightInfo.height) > 1) {
			isBalanced = false;
		}
		// 加工出当前节点的信息返回
		return new Info(isBalanced, 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 (isBalanced1(head) != isBalanced2(head)) {
				System.out.println("Oops!");
			}
		}
		System.out.println("finish!");
	}

}

.1.2 例二:返回二叉树任意两个节点最大值

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

1、有可能最大距离和当前节点X无关,即最大距离是X左树的最大距离,或者右树的最大距离

2、最大距离跟X有关,即最大距离通过X。左树离X最远的点,到X右树上离X最远的点。即X左树的高度加上X自身高度1,加上X右树上的高度

结论:那么根据递归套路,我们每次递归,需要返回X左树的最大距离和高度,同理返回X右树的最大距离和高度。Info包含最大距离和高度

package class08;

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

public class Code08_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 lo
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值