左神算法笔记(十九)——树型DP(动态规划)

题目一

求整颗二叉树的最大搜索二叉子树

逻辑:将整个题目转成以每个节点作为头的最大搜索二叉子树,最大的搜索二叉子树一定在其中。基本二叉树的题目都可以利用这样的思想进行求解。

思路

思路:当前节点的最大搜索子树可能来自于
左子树的某个子树,
右子树的某个子树,
左子树是搜索二叉树,右子树也是搜索二叉树,并且左子树的最大值小于我,右子树的最小值大于我,则以我为头为整个搜索二叉子树

主逻辑:对每个节点进行上述的分析
详细点:子树如何进行判断上述的过程,需要搜集哪些信息。
1. 左树最大搜索二叉树大小,头部
2. 右部最大搜索二叉树大小,头部
3. 左树上的最大值
4. 右树上的最小值
有了以上的信息,则可以计算出上述的三种情况。

因为整个信息会在递归中展示,所以需要将上述消息体进行整合
1. 搜大小
2. 搜头部
3. 当前树最大
4. 当前树最小
上述三点为精简后的消息体,对于左边还是右边,最后上传的内容体都相同,不区分左右。这样会更加具有普遍性,此时可以进行递归,从而实现算法。

整体套路

递归的整个过程:
1. 明确可能性情况
2. 明确需要的参数内容
3. 将参数当做黑盒对待,假设下面的节点可以直接返回该形式,改递归。
4. 将可能性分别列出
5. 将黑盒展开,明确当前节点需要返回的内容,编写代码实现。

代码

//首先明确好返回值的类型,都需要返回的内容
public static class ReturnType{
	public int size;
	public Node head;
	public int min;
	public int max;
	public ReturnType(int a,Node b,int c,int d){
		this.size = a;
		this.head = b;
		this.min = c;
		this.max = d;
	}
}
//递归的整个过程,按照上述所分的三种可能进行分析
public static ReturnType process(Node head){
	//如果现在的节点为空了,则证明无节点,所以将对应的信息放进去,最小的设置成系统最大值,最大的设置成系统最小值,对于算法来说不影响。
	if(head == null){
		return new ReturnType(0,null,Integer.MAX_VALUE,Integer.MIN_VALUE);
	}
	//明确好需要返回的值,此时相信左子树和右子树会给我我想要的内容。递归形式在这里确立
	Node left = head.left;
	ReturnType leftSubTreessInfo = process(left);
	Node right = head.right;
	ReturnType rightSubTreessInfo = process(right);
	int includeItself = 0;
	//如果满足下面的if判断,则意味着包含当前节点可以形成搜索二叉树
	if(leftSubTreessInfo.head == left
		&&rightSubTreessInfo.head ==right
		&&head.value > leftSubTreessInfo.max
		&&head.value < rightSubTreessInfo.min
		){
		includeItself = leftSubTreessInfo.size +1+ rightSubTreessInfo.size;
	}
	//无论上面判断是否成立,下面的代码都将执行,确立递归中元素的值,下面分别确定maxsize,和maxHead。
	int p1 = leftSubTreessInfo.size;
	int p2 = rightSubTreessInfo.size;
	int maxSize = Math.max(Math.max(p1,p2),includeItself);
	
	Node maxHead = p1 >p2 ? leftSubTreessInfo.head :rightSubTreessInfo.head;
	if(maxSize == includeItself){
		maxHead =head;	
	}

	return new ReturnType(maxSize,
		maxHead,
		Math.min(Math.min(leftSubTreessInfo.min,rightSubTreessInfo.min),head.value),
		Math,max(Math.max(leftSubTreessInfo.max,rightSubTreessInfo.max),head.value));
}
		
	

上述代码就是描述了整个二叉树递归的过程,确立好递归的思路,确立好递归需要的内容,之后编写代码实现递归的过程。此时时间复杂度还是O(N),每个节点仅遍历一遍,就可以得到当前节点的对应信息给父节点,不需要再遍历,中间的过程数据传输的复杂度为O(1)。

题目二

左神算法笔记(十九)——树型DP(动态规划)_第1张图片

思路

跟上一题一样,套路的思路:以当前节点求出他子树中的最长距离,则求出每一个节点时,最大距离必定在其中。

情况分析:
1. 最大距离来自左子树
2. 最大距离来自右子树
3. 最大距离跟当前节点相关,则最大距离为左树距离和右树距离再加上自己这个点。
需要的信息:
1. 左长距离
2. 右长距离
3. 左深+右深

整合之后的信息:
1. 最长距离
2. 深度

代码

//整合的信息
public static class ReturnType{
	public int maxDistance;
	public int h;

	public ReturnType(int m,int h){
		this.maxDistance = m;
		this.h = h;
	}
}
//递归整个流程

public static ReturnType process(Node head){
	if(head ==null){
		return new ReturnType(0,0);
	}
	ReturnType leftReturnType = process(head.left);
	ReturnType rightReturnType = process(head.right);
	int includeHeadDistance = leftReturnType.h + rightReturnType.h;
	int p1 = leftReturnType.maxDistance;
	int p2 = rightReturnType.maxDistance;
	int resultDistance = Math.max(Math.max(p1,p2),includeHeadDistance);
	int hitself = Math.max(leftReturnType.h,rightReturnType.h) +1;
	return new ReturnType(resultDistance,hitself);
}

//返回给主函数结果
public static int getMaxD(Node head){
	return process(head).maxDistance;
}

题目三

左神算法笔记(十九)——树型DP(动态规划)_第2张图片

思路

同样的情况,如果我可以求出每一个节点子树中最活跃的情况,则最后最活跃的情况一定包含在其中。

自己的分析

分情况:
1. 当前节点最活跃的情况包含当前节点,则它的子节点一定不在其中。活跃度为所有孙子节点的最大活跃度之和再加上当前节点的活跃度。
2. 当前节点最活跃的情况不包含当前节点,则他最活跃的情况是所有子树最大活跃度之和。

需要的信息:
1. 子节点的最大活跃度和
2. 孙子节点的最大活跃度和。
其实来的最大活跃度信息对应着孙子节点的最大活跃度之和。不来的最大活跃度对应着子节点的最大活跃度之和。但是会涉及到孙子节点信息,可能需要加额外的判断。

左神的分析

分情况:
1. 最活跃包含当前节点,子节点一定不来,子节点不来的最大活跃度
2. 不包含当前节点,最大值为所有子节点来或不来中的最大值之和。

需要的信息:
1. 来的最大活跃度
2. 不来的最大活跃度

代码

public static class ReturnData{
	public int lai_huo;
	public int bulai_huo;
	public ReturnData(int lai_huo,int bulai_huo){
		this.lai_huo = laihuo;
		this.bulai_huo = bulai_huo;
	}
}

public static ReturnData process(Node head){
	int lai_huo = head.huo;
	int bulai_huo = 0;
	//遍历每一个后代,拿到每一个后代之后,返回信息。
	for(int i = 0;i < head.nexts.size();i++){
		Node next = head.nexts.get(i);
		ReturnData nextData = process(next);
		lai_huo += nexData.bulai_huo;
		bulai_huo += Math.max(nextData.lai_huo,nextData.bulai_huo);
	}
	return new ReturnData(lai_huo,bulai_huo);

你可能感兴趣的:(左神算法专栏)