class078 Tree dp-Part 1 [Algorithm]

class078 Tree dp-Part 1 [Algorithm]

Algorithm Explanation 078 [Required] Tree dp-Part 1

Insert image description here

Insert image description here

code1 333. Maximum BST subtree

// Maximum BST subtree
// Given a binary tree, find the largest binary search tree (BST) subtree and return the size of the subtree a> a> // Test link: https://leetcode.cn/problems/largest-bst-subtree/ // Note: The subtree must contain all its descendants // The value of the right subtree is greater than the value of its parent (root) node // The value of the left subtree is less than the value of its parent (root) node // All nodes in the binary search tree (BST) have the following attributes:
// Among them, the largest refers to the one with the largest number of subtree nodes




Tree dp:
maxBstSize of the entire tree at the x head
excluding x: max (left tree maxBstSize, right tree maxBstSize) So you need to return the value (maxBstSize, isBst, max, min)
Contains x: left tree isBst, right tree isBst, left tree max, right tree min, if max<x<min, return: left tree maxBstSize+right tree maxBstSize+1

Empty tree returns [0,true,MAX,MIN]

Similar to post-order traversal: get the return value of the child, then integrate your own return value, and finally return it to the upper layer

package class078;

// 最大BST子树
// 给定一个二叉树,找到其中最大的二叉搜索树(BST)子树,并返回该子树的大小
// 其中,最大指的是子树节点数最多的
// 二叉搜索树(BST)中的所有节点都具备以下属性:
// 左子树的值小于其父(根)节点的值
// 右子树的值大于其父(根)节点的值
// 注意:子树必须包含其所有后代
// 测试链接 : https://leetcode.cn/problems/largest-bst-subtree/
public class Code01_LargestBstSubtree {
    
    

	// 不要提交这个类
	public static class TreeNode {
    
    
		public int val;
		public TreeNode left;
		public TreeNode right;
	}

	// 提交如下的方法
	public static int largestBSTSubtree(TreeNode root) {
    
    
		return f(root).maxBstSize;
	}

	public static class Info {
    
    
		public long max;
		public long min;
		public boolean isBst;
		public int maxBstSize;

		public Info(long a, long b, boolean c, int d) {
    
    
			max = a;
			min = b;
			isBst = c;
			maxBstSize = d;
		}
	}

	public static Info f(TreeNode x) {
    
    
		if (x == null) {
    
    
			return new Info(Long.MIN_VALUE, Long.MAX_VALUE, true, 0);
		}
		Info infol = f(x.left);
		Info infor = f(x.right);
		// 左 4信息
		// 右 4信息
		// x 整合出4信息返回
		long max = Math.max(x.val, Math.max(infol.max, infor.max));
		long min = Math.min(x.val, Math.min(infol.min, infor.min));
		boolean isBst = infol.isBst && infor.isBst && infol.max < x.val && x.val < infor.min;
		int maxBSTSize;
		if (isBst) {
    
    
			maxBSTSize = infol.maxBstSize + infor.maxBstSize + 1;
		} else {
    
    
			maxBSTSize = Math.max(infol.maxBstSize, infor.maxBstSize);
		}
		return new Info(max, min, isBst, maxBSTSize);
	}

}

code2 1373. Maximum key value sum of binary search subtree

//The maximum key value sum of the binary search subtree
//Give you a binary tree with root as the root
//Please You return the maximum key value sum of any binary search subtree
// The definition of a binary search tree is as follows:
// In the left subtree of any node The key values ​​are all less than the key value of this node
// The key values ​​in the right subtree of any node are greater than the key value of this node
// Any The left subtree and right subtree of the node are both binary search trees
// Test link: https://leetcode.cn/problems/maximum-sum-bst-in-binary-tree /

maxBstSum of the whole tree of x head
does not include x: max (left maxBstSum, right maxBstSum)
includes x: left isBst, right isBst, Left max, right min, if max<x<min returns left sum+right sum+x.val
Integration (max, min, sum, isBst, maxBstSum)
Empty tree returns (MAX,MIN,0,true,0)

package class078;

// 二叉搜索子树的最大键值和
// 给你一棵以 root 为根的二叉树
// 请你返回 任意 二叉搜索子树的最大键值和
// 二叉搜索树的定义如下:
// 任意节点的左子树中的键值都 小于 此节点的键值
// 任意节点的右子树中的键值都 大于 此节点的键值
// 任意节点的左子树和右子树都是二叉搜索树
// 测试链接 : https://leetcode.cn/problems/maximum-sum-bst-in-binary-tree/
public class Code02_MaximumSumBst {
    
    

	// 不要提交这个类
	public static class TreeNode {
    
    
		public int val;
		public TreeNode left;
		public TreeNode right;
	}

	// 提交如下的方法
	public static int maxSumBST(TreeNode root) {
    
    
		return f(root).maxBstSum;
	}

	public static class Info {
    
    
		// 为什么这里的max和min是int类型?
		// 因为题目的数据量规定,
		// 节点值在[-4 * 10^4,4 * 10^4]范围
		// 所以int类型的最小值和最大值就够用了
		// 不需要用long类型
		public int max;
		public int min;
		public int sum;
		public boolean isBst;
		public int maxBstSum;

		public Info(int a, int b, int c, boolean d, int e) {
    
    
			max = a;
			min = b;
			sum = c;
			isBst = d;
			maxBstSum = e;
		}
	}

	public static Info f(TreeNode x) {
    
    
		if (x == null) {
    
    
			return new Info(Integer.MIN_VALUE, Integer.MAX_VALUE, 0, true, 0);
		}
		Info infol = f(x.left);
		Info infor = f(x.right);
		int max = Math.max(x.val, Math.max(infol.max, infor.max));
		int min = Math.min(x.val, Math.min(infol.min, infor.min));
		int sum = infol.sum + infor.sum + x.val;
		boolean isBst = infol.isBst && infor.isBst && infol.max < x.val && x.val < infor.min;
		int maxBstSum = Math.max(infol.maxBstSum, infor.maxBstSum);
		if (isBst) {
    
    
			maxBstSum = Math.max(maxBstSum, sum);
		}
		return new Info(max, min, sum, isBst, maxBstSum);
	}

}

code3 543. Diameter of binary tree

// The diameter of the binary tree
// Give you the root node of a binary tree and return the diameter of the tree
// The diameter of the binary tree is Refers to the length of the longest path between any two nodes in the tree
// This path may or may not pass through the root node root
// Two nodes The length of the path between them is represented by the number of edges between them
// Test link: https://leetcode.cn/problems/diameter-of-binary-tree/

Diameter of x head
Does not include x: max (left diameter, right diameter)
Includes x: left maximum depth + right maximum depth ( Without adding 1, the number of edges is 1 less than the number of points)

Returns (diameter, height)
Empty tree returns (0,0)

package class078;

// 二叉树的直径
// 给你一棵二叉树的根节点,返回该树的直径
// 二叉树的 直径 是指树中任意两个节点之间最长路径的长度
// 这条路径可能经过也可能不经过根节点 root
// 两节点之间路径的 长度 由它们之间边数表示
// 测试链接 : https://leetcode.cn/problems/diameter-of-binary-tree/
public class Code03_DiameterOfBinaryTree {
    
    

	// 不要提交这个类
	public static class TreeNode {
    
    
		public int val;
		public TreeNode left;
		public TreeNode right;
	}

	// 提交如下的方法
	public static int diameterOfBinaryTree(TreeNode root) {
    
    
		return f(root).diameter;
	}

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

		public Info(int a, int b) {
    
    
			diameter = a;
			height = b;
		}

	}

	public static Info f(TreeNode x) {
    
    
		if (x == null) {
    
    
			return new Info(0, 0);
		}
		Info leftInfo = f(x.left);
		Info rightInfo = f(x.right);
		int height = Math.max(leftInfo.height, rightInfo.height) + 1;
		int diameter = Math.max(leftInfo.diameter, rightInfo.diameter);
		diameter = Math.max(diameter, leftInfo.height + rightInfo.height);
		return new Info(diameter, height);
	}

}

code4 979. Distribute coins in a binary tree

// Distribute coins in a binary tree
// Give you the root node root of a binary tree with n nodes
// where Each node node in the tree corresponds to node.val coins
// There are a total of n coins in the entire tree
// In one move , we can select two adjacent nodes, and then move a coin from one of the nodes to the other node
// The movement can be from the parent node to the child node , or move from a child node to a parent node
// Return the minimum number of moves required to make each node have only one coin
// Test link: https://leetcode.cn/problems/distribute-coins-in-binary-tree/

Tree with x as head, several parts
Number of left steps + number of right steps +|Left node tree-number of left coins|+|Right node tree-right coins Number|
Return (number of steps, sum of nodes, sum of coins)

package class078;

// 在二叉树中分配硬币
// 给你一个有 n 个结点的二叉树的根结点 root
// 其中树中每个结点 node 都对应有 node.val 枚硬币
// 整棵树上一共有 n 枚硬币
// 在一次移动中,我们可以选择两个相邻的结点,然后将一枚硬币从其中一个结点移动到另一个结点
// 移动可以是从父结点到子结点,或者从子结点移动到父结点
// 返回使每个结点上 只有 一枚硬币所需的 最少 移动次数
// 测试链接 : https://leetcode.cn/problems/distribute-coins-in-binary-tree/
public class Code04_DistributeCoins {
    
    

	// 不要提交这个类
	public static class TreeNode {
    
    
		public int val;
		public TreeNode left;
		public TreeNode right;
	}

	// 提交如下的方法
	public static int distributeCoins(TreeNode root) {
    
    
		return f(root).move;
	}

	public static class Info {
    
    
		public int cnt;
		public int sum;
		public int move;

		public Info(int a, int b, int c) {
    
    
			cnt = a;
			sum = b;
			move = c;
		}
	}

	public static Info f(TreeNode x) {
    
    
		if (x == null) {
    
    
			return new Info(0, 0, 0);
		}
		Info infol = f(x.left);
		Info infor = f(x.right);
		int cnts = infol.cnt + infor.cnt + 1;
		int sums = infol.sum + infor.sum + x.val;
		int moves = infol.move + infor.move + Math.abs(infol.cnt - infol.sum) + Math.abs(infor.cnt - infor.sum);
		return new Info(cnts, sums, moves);
	}

}

code5 P1352 A dance without a boss

// A dance without a boss
// There are n employees in a university, numbered 1...n
// There are subordinates among them Relationship, that is to say, their relationship is like a tree with the principal as the root
// The parent node is the direct boss of the child node
// There is an anniversary party now. Every time an employee is invited to the party, the happiness index will increase by a certain amount
// But if an employee’s direct boss comes to the party
// Then this employee will not come to the dance no matter what
// So please program and calculate which employees to invite to maximize the happiness index
/ / Returns the maximum happiness index.
// Test link: https://www.luogu.com.cn/problem/P1352
// This question is similar to question 7 of explanation 037 a> // Submit the following code, please change the class name to " when submitting. ;Main", you can directly pass // This is a very efficient way of writing input and output processing // Please be sure to refer to the following code for input , Output processing
// Chain link: https://leetcode.cn/problems/house-robber-iii/


Numbers starting with x
x: x+numbers starting with a+numbers starting with b+numbers starting with c+…< /span>
x does not come: the number starting with a max (come, not come) + the number starting with b max (come, not come) + the number starting with c max (come, Not coming)

Integrate return (come, don't come)

package class078;

// 没有上司的舞会
// 某大学有n个职员,编号为1...n
// 他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树
// 父结点就是子结点的直接上司
// 现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 
// 但是如果某个职员的直接上司来参加舞会了
// 那么这个职员就无论如何也不肯来参加舞会了
// 所以请你编程计算邀请哪些职员可以使快乐指数最大
// 返回最大的快乐指数。
// 测试链接 : https://www.luogu.com.cn/problem/P1352
// 本题和讲解037的题目7类似
// 链式链接 : https://leetcode.cn/problems/house-robber-iii/
// 请同学们务必参考如下代码中关于输入、输出的处理
// 这是输入输出处理效率很高的写法
// 提交以下的code,提交时请把类名改成"Main",可以直接通过

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.Arrays;

public class Code05_Dancing {
    
    

	public static int MAXN = 6001;

	public static int[] nums = new int[MAXN];

	public static boolean[] boss = new boolean[MAXN];

	// 链式前向星建图
	public static int[] head = new int[MAXN];

	public static int[] next = new int[MAXN];

	public static int[] to = new int[MAXN];

	public static int cnt;

	// 动态规划表
	// no[i] : i为头的整棵树,在i不来的情况下,整棵树能得到的最大快乐值
	public static int[] no = new int[MAXN];

	// no[i] : i为头的整棵树,在i来的情况下,整棵树能得到的最大快乐值
	public static int[] yes = new int[MAXN];

	public static int n, h;

	public static void build(int n) {
    
    
		Arrays.fill(boss, 1, n + 1, true);
		Arrays.fill(head, 1, n + 1, 0);
		cnt = 1;
	}

	public static void addEdge(int u, int v) {
    
    
		next[cnt] = head[u];
		to[cnt] = v;
		head[u] = cnt++;
	}

	public static void main(String[] args) throws IOException {
    
    
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StreamTokenizer in = new StreamTokenizer(br);
		PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
		while (in.nextToken() != StreamTokenizer.TT_EOF) {
    
    
			n = (int) in.nval;
			build(n);
			for (int i = 1; i <= n; i++) {
    
    
				in.nextToken();
				nums[i] = (int) in.nval;
			}
			for (int i = 1, low, high; i < n; i++) {
    
    
				in.nextToken();
				low = (int) in.nval;
				in.nextToken();
				high = (int) in.nval;
				addEdge(high, low);
				boss[low] = false;
			}
			for (int i = 1; i <= n; i++) {
    
    
				if (boss[i]) {
    
    
					h = i;
					break;
				}
			}
			f(h);
			out.println(Math.max(no[h], yes[h]));
		}
		out.flush();
		out.close();
		br.close();
	}

	
	public static void f(int u) {
    
    
		no[u] = 0;
		yes[u] = nums[u];
		for (int ei = head[u], v; ei > 0; ei = next[ei]) {
    
    
			v = to[ei];
			f(v);
			no[u] += Math.max(no[v], yes[v]);
			yes[u] += no[v];
		}
	}

}

code6 968. Monitor binary trees

// Monitoring Binary Tree
// Given a binary tree, we install cameras on the nodes of the tree
// Each photography on the node The header can monitor its parent object, itself and its direct child objects
// Calculate the minimum number of cameras required to monitor all nodes of the tree
// Test link : https://leetcode.cn/problems/binary-tree-cameras/

Three states
0: x is not covered, but the bottom part is covered
1: x is covered, but there is no camera on x
2: x is covered and there is a camera on x

If there is any 0 on the left and right, x is replaced with 2
If there is 1 on the left and right, x is replaced with 0
There are 12 21 22 on the left and right, x Put back 0

Empty tree returns 1

package class078;

// 监控二叉树
// 给定一个二叉树,我们在树的节点上安装摄像头
// 节点上的每个摄影头都可以监视其父对象、自身及其直接子对象
// 计算监控树的所有节点所需的最小摄像头数量
// 测试链接 : https://leetcode.cn/problems/binary-tree-cameras/
public class Code06_BinaryTreeCameras {
    
    

	// 不要提交这个类
	public static class TreeNode {
    
    
		public int val;
		public TreeNode left;
		public TreeNode right;
	}

	// 提交如下的方法
	public int minCameraCover(TreeNode root) {
    
    
		ans = 0;
		if (f(root) == 0) {
    
    
			ans++;
		}
		return ans;
	}
	
	// 遍历过程中一旦需要放置相机,ans++
	public static int ans;

	// 递归含义
	// 假设x上方一定有父亲的情况下,这个假设很重要
	// x为头的整棵树,最终想都覆盖,
	// 并且想使用最少的摄像头,x应该是什么样的状态
	// 返回值含义
	// 0: x是无覆盖的状态,x下方的节点都已经被覆盖
	// 1: x是覆盖状态,x上没摄像头,x下方的节点都已经被覆盖
	// 2: x是覆盖状态,x上有摄像头,x下方的节点都已经被覆盖
	private int f(TreeNode x) {
    
    
		if (x == null) {
    
    
			return 1;
		}
		int left = f(x.left);
		int right = f(x.right);
		if (left == 0 || right == 0) {
    
    
			ans++;
			return 2;
		}
		if (left == 1 && right == 1) {
    
    
			return 0;
		}
		return 1;
	}

}

code7 437. Path sum III

// Path sum III
// Given the root node root of a binary tree, and an integer targetSum
// Find the nodes in the binary tree The number of paths whose sum of values ​​is equal to targetSum
// The path does not need to start from the root node, nor does it need to end at the leaf node
// But the path direction must It is downward (only from parent node to child node)
// Test link: https://leetcode.cn/problems/path-sum-iii/

sum: Starting from the head node, when arriving at x, what is the cumulative sum above?
The path must end with variable ans on

package class078;

import java.util.HashMap;

// 路径总和 III
// 给定一个二叉树的根节点 root ,和一个整数 targetSum
// 求该二叉树里节点值之和等于 targetSum 的 路径 的数目
// 路径 不需要从根节点开始,也不需要在叶子节点结束
// 但是路径方向必须是向下的(只能从父节点到子节点)
// 测试链接 : https://leetcode.cn/problems/path-sum-iii/
public class Code07_PathSumIII {
    
    

	// 不要提交这个类
	public static class TreeNode {
    
    
		public int val;
		public TreeNode left;
		public TreeNode right;
	}

	// 提交如下的方法
	public static int pathSum(TreeNode root, int sum) {
    
    
		HashMap<Long, Integer> presum = new HashMap<>();
		presum.put(0L, 1);
		ans = 0;
		f(root, sum, 0, presum);
		return ans;
	}

	public static int ans;

	// sum : 从头节点出发,来到x的时候,上方累加和是多少
	// 路径必须以x作为结尾,路径累加和是target的路径数量,累加到全局变量ans上
	public static void f(TreeNode x, int target, long sum, HashMap<Long, Integer> presum) {
    
    
		if (x != null) {
    
    
			sum += x.val; // 从头节点出发一路走到x的整体累加和
			ans += presum.getOrDefault(sum - target, 0);
			presum.put(sum, presum.getOrDefault(sum, 0) + 1);
			f(x.left, target, sum, presum);
			f(x.right, target, sum, presum);
			presum.put(sum, presum.get(sum) - 1);
		}
	}

}

Guess you like

Origin blog.csdn.net/qq_51625007/article/details/134612253