数据结构与算法:树型dp
前言
树型dp就是在树上做动态规划,能用到的思想和套路在之后进阶的树上图上算法里很重要。
一、内容
在树上做动态规划时,对于不同的可能性展开,大多需要递归函数返回多个不同的信息,所以在树型dp里需要用一个Info类包装所有需要的信息,不管当前递归函数用没用到,都要更新所有的信息,并直接返回这个Info类。
二、题目
1.最大二叉搜索子树
这题需要VIP,等我有了之后再来写()
2.二叉搜索子树的最大键值和
class Solution {
public://所有需要的信息class Info{public:int Max;int Min;int sum;bool isBST;int maxBSTSum;Info(int a,int b,int c,bool d,int e){Max=a;Min=b;sum=c;isBST=d;maxBSTSum=e;}};int maxSumBST(TreeNode* root) {return f(root).maxBSTSum;}Info f(TreeNode* root){if(root==NULL){//空树键值和设置为0 -> 啥也不要return Info(INT_MIN,INT_MAX,0,true,0);}//讨论要x节点和不要x节点//要x节点时,需要满足左树、右树和加上x节点后都是二叉搜索树,以及整体累加和//不要X节点时,需要左树和右树的最大键值和//先去左右孩子收集信息Info left=f(root->left);Info right=f(root->right);//整合信息int Max=max(left.Max,max(right.Max,root->val));int Min=min(left.Min,min(right.Min,root->val));int sum=left.sum+right.sum+root->val;bool isBST=left.isBST&&right.isBST&&left.Max<root->val&&root->val<right.Min;int maxBSTSum=max(left.maxBSTSum,right.maxBSTSum);if(isBST){maxBSTSum=max(maxBSTSum,sum);}return Info(Max,Min,sum,isBST,maxBSTSum);}
};
树型dp的套路还是先分析可能性。对于来到的每个节点,可能当前节点不参与构成最大键值和,也可能当前节点参与构成键值和。对于不参与的情况,当前最大键值和就是左树和右树的最大键值和的最大值。对于参与的情况,首先需要保证左右树是二叉搜索树,且加上当前节点后也是二叉搜索树,在这个基础上,还需要左右树的整体累加和。而因为要判断加上当前节点是否是二叉搜索树,所以还需要左树的最大值和右树的最小值。
整合一下,Info类里就应该包含max,min,sum,bool类型的isBST以及最大键值和maxBSTsum这几个变量。
所以来到每个节点就先去左右孩子调递归收集信息,接着整合出当前节点的信息返回即可。
3.二叉树的直径
class Solution {
public:class Info{public:int diameter;int height;Info(int a,int b){diameter=a;height=b;}};int diameterOfBinaryTree(TreeNode* root) {return f(root).diameter;}Info f(TreeNode* root){if(root==NULL){return Info(0,0);}//讨论经过x节点和不经过x节点//不经过x节点时,需要左树和右树的直径//经过x节点时,需要左树和右树的最大深度Info left=f(root->left);Info right=f(root->right);int diameter=max(left.diameter,right.diameter);//不经过x节点时的直径int height=max(left.height,right.height)+1;diameter=max(diameter,left.height+right.height);//注意!!不加1!!return Info(diameter,height);}
};
这个题的可能性展开还是分成经过当前节点和不经过当前节点两种情况展开。
先整合需要的信息,对于经过当前节点的情况,那最大直径就是左树和右树的深度相加。对于不经过当前节点的情况,最大直径就是左树和右树的最大直径。
4.在二叉树中分配硬币
class Solution {
public:class Info{public:int cnt;int sum;int move;Info(int a,int b,int c){cnt=a;sum=b;move=c;}};int distributeCoins(TreeNode* root) {return dfs(root).move;}Info dfs(TreeNode* root){if(root==NULL){return Info(0,0,0);}//对于x节点,需要统计左树和右树走的步数,以及需要调配的数量Info left=dfs(root->left);Info right=dfs(root->right);int cnt=left.cnt+right.cnt+