树形dp套路

https://www.cnblogs.com/mhpp/p/6628548.html

树形dp套路 树形dp套路使用前提: 如果题目求解目标是S规则,则求解流程可以定成以每一个节点为头节点的子树在S规则下的每一个答案,并且最终答案一定在其中

 

1. 树形dp套路

【站在 左树也能要信息,右树也能要信息,考虑当前头的角度】

树形dp套路第一步:

以某个节点X为头节点的子树中,分析答案有哪些可能性,并且这种分析是以X的左子树、X的右子树和X整棵树的角度来考虑可能性的

树形dp套路第二步:

根据第一步的可能性分析,列出所有需要的信息

树形dp套路第三步:

合并第二步的信息,对左树和右树提出同样的要求,并写出信息结构

树形dp套路第四步:

设计递归函数,递归函数是处理以X为头节点的情况下的答案。

包括设计递归的basecase,默认直接得到左树和右树的所有信息,以及把可能性做整合,并且要返回第三步的信息结构这四个小步骤

 

题目一  :二叉树节点间的最大距离问题

从二叉树的节点a出发,可以向上或者向下走,但沿途的节点只能经过一次,到达节点b时路径上的节点个数叫作a到b的距离,那么二叉树任何两个节点之间都有距离,求整棵树上的最大距离

 

1. 以X的左子树、X的右子树和X整棵树的角度来考虑可能性的

1) 和x有关,那就是左子树上最长的 到x 然后 到右子树

2) 和x无关

    A. 只与x的左子树有关 [ 如下图 ]

    B. 只与x的右子树有关

树形dp套路

2. 根据第一步的可能性分析,列出所有需要的信息

左远到右远

左树上的最大距离,左远对应的左树的高度。

右树上的最大距离,右远对应的右树的高度。

树形dp套路

3.合并第二步的信息,对左树和右树提出同样的要求,并写出信息结构【求并集】

如左树要最小,右树要最大,那么信息结构就是两者都要求。树形dp套路

4.设计递归函数,递归函数是处理以X为头节点的情况下的答案。

包括设计递归的basecase,默认直接得到左树和右树的所有信息,以及把可能性做整合,并且要返回第三步的信息结构这四个小步骤

public class Code02_MaxDistanceInTree {

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

		public Node(int data) {
			this.value = data;
		}
	}
	
	// 主函数,得到最大距离,输入一个头结点
	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) {//通过proess函数得到info
        // 1. basecase
		if(x == null) {
			return new Info(0,0);//构造新的info返回
		}
        // 2. 默认直接得到左树和右树的所有信息
		Info leftInfo = process(x.left);// 用了黑盒
		Info rightInfo = process(x.right);
		// info 拆解黑盒,拆出该函数的意义 ,这里是得到info【maxDistance,height】
        // 3. 可能性做整合 拆解黑盒
		int p1 = leftInfo.maxDistance;//情况一
		int p2 = rightInfo.maxDistance;//情况二
		int p3 = leftInfo.height + 1 + rightInfo.height;//情况三
		int maxDistance = Math.max(p3, Math.max(p1, p2));
		int height = Math.max(leftInfo.height, rightInfo.height) + 1 ;
        // 4. 返回第三步的信息结构
		return new Info(maxDistance, height);
	}
}


题目二 派对的最大快乐值  

员工信息的定义如下:

class Employee {    

              public int happy; // 这名员工可以带来的快乐值    

              List<Employee> subordinates; // 这名员工有哪些直接下级 }

公司的每个员工都符合 Employee 类的描述。整个公司的人员结构可以看作是一棵标准的、 没有环的多叉树。树的头节点是公司唯一的老板。除老板之外的每个员工都有唯一的直接上级。 叶节点是没有任何下属的基层员工(subordinates列表为空),除基层员工外,每个员工都有一个或多个直接下级。 这个公司现在要办party,你可以决定哪些员工来,哪些员工不来。但是要遵循如下规则。

1.如果某个员工来了,那么这个员工的所有直接下级都不能来

2.派对的整体快乐值是所有到场员工快乐值的累加

3.你的目标是让派对的整体快乐值尽量大

给定一棵多叉树的头节点boss,请返回派对的最大快乐值。

 

首先从X开始分析,x整棵树可能性

树形dp套路

	public static class Employee { 
		public int happy; // 这名员工可以带来的快乐值 
	    public List<Employee> nexts; // 这名员工有哪些直接下级 
	}
	
	
	public static int maxHappy(Employee boss) {
		Info headInfo = process(boss);
		return Math.max(headInfo.laiMaxHappy, headInfo.buMaxHappy);
	}
	
	// 得到一个员工,来or不来,分别对应的最大happy!!!!
	public static class Info{
		public int laiMaxHappy;
		public int buMaxHappy;
		public Info(int lai, int bu) {
			laiMaxHappy = lai;
			buMaxHappy = bu;
		}
	}
	// 得到一个员工,来or不来,分别对应的最大happy!!!!
	public static Info process(Employee x) {
		//1. basecase
		if(x.nexts.isEmpty()) {
			return new Info(x.happy,0);
		}
		int lai = x.happy;
		int bu = 0;
		for(Employee next : x.nexts) {
			Info nextInfo = process(next);// 2. 默得到子树的info信息
			// 3. 整合信息【拆解黑盒,得到info中具体的】
			lai += nextInfo.buMaxHappy;
			bu += Math.max(nextInfo.laiMaxHappy, nextInfo.buMaxHappy);
		}// 4. 返回info
		return new Info(lai,bu);
	}

 

题目三 最大搜索二叉子树

树形dp套路

package class05;

public class MaxBSTSize {

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

	public static class Info {
		public int maxBSTSize;
		public boolean isBST;
		public int min;
		public int max;

		public Info(int maxBST, boolean is, int mi, int ma) {
			maxBSTSize = maxBST;
			isBST = is;
			min = mi;
			max = ma;
		}
	}

	public static Info  process(Node x){
		if(x == null) {
			// 不想子树感染上级,最小值给系统最大,
			return new Info(0,true,Integer.MAX_VALUE,Integer.MIN_VALUE);
		}
		Info leftInfo = process(x.left);
		Info rightInfo = process(x.right);
		boolean isBST = false;
		int maxBSTSize = leftInfo.maxBSTSize;
		maxBSTSize = Math.max(maxBSTSize,rightInfo.maxBSTSize);
		if(leftInfo.isBST 
				&& rightInfo.isBST 
				&& leftInfo.max < x.value 
				&& rightInfo.min > x.value) {
			maxBSTSize = leftInfo.maxBSTSize + 1 + rightInfo.maxBSTSize;
			isBST = true;
		}
		int min = Math.min(x.value, Math.min(leftInfo.min, rightInfo.min));
		int max = Math.max(x.value, Math.max(leftInfo.max, rightInfo.max));
		 return new Info(maxBSTSize,isBST,min,max);
		
	}

}