每日算法总结——树型DP套路

树型dp套路

  • 树形dp套路第一步:
    以某个节点X为头节点的子树中,分析答案有哪些可能性,并且这种分析是以X的左子树、X的右子树和X整棵树的角度来考虑可能性的
  • 树形dp套路第二步: .
    根据第一步的可能性分析,列出所有需要的信息
  • 树形dp套路第三步:
    合并第二步的信息,对左树和右树提出同样的要求,并写出信息结构
  • 树形dp套路第四步:
    设计递归函数,递归函数是处理以X为头节点的情况下的答案。
    包括设计递归的basecase,默认直接得到左树和右树的所有信息,以及把可能性做整合,并且要返回第三步的信息结构这四个小步骤
实战1

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

LeetCode原题543. 二叉树的直径 - 力扣(LeetCode)

难度Esay

解题思路

  • 一棵树的节点间最大距离,可以分为包含根节点和不包含根节点两种情况
    • 不包含根节点:则最大距离为MAX(左子树最大距离,右子树最大距离)
    • 包含根节点:则最大距离为MAX(左子树最大距离,右子树最大距离,左子树高度+右子树高度)
class Solution {
    class Info {
        int height;
        int maxDistance;
        public Info(int a, int b) {
            height = a;
            maxDistance = b;
        }
    }
    public int diameterOfBinaryTree(TreeNode root) {
        return getInfo(root).maxDistance;
    }

    public Info getInfo(TreeNode node) {
        if (node == null) {
            return new Info(0, 0);
        }
        Info left = getInfo(node.left);
        Info right = getInfo(node.right);
        return new Info(Math.max(left.height, right.height) + 1, Math.max(Math.max(left.maxDistance, right.maxDistance), left.height + right.height));
    }
}
实战2

题目:派对的最大快乐值

员工信息的定义如下:

class Employee {
	public int happy; //这名员工可以带来的快乐值
	List<Employee> subordinates; //这名员工有哪些直接下级
}

公司的每个员工都符合Employee类的描述。整个公司的人员结构可以看作是一棵标准的、没有环的多叉树。树的头节点是公司唯一的老板。除老板之外的每个员工都有唯一的直接上级。叶节点是没有任何下属的基层员工(subordinates列表为空),除基层员工外,每个员工都有一个或多个直接下级。

这个公司现在要办party,你可以决定哪些员工来,哪些员工不来。但是要遵循如下规则。

  1. 如果某个员工来了,那么这个员工的所有直接下级都不能来
  2. 派对的整体快乐值是所有到场员工快乐值的累加
  3. 你的目标是让派对的整体快乐值尽量大

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

解题思路

  • 首先分析一下题目,每个员工(包括老板)都有来与不来两种选择
    • 如果上级员工来了,则他的直接下级员工就一定不来
    • 如果上级员工不来,则他的直接下级员工就可以来也可以不来
  • 每个员工在这道题中都是一个树节点,每个节点可以有多个子节点,即多个子树。
    对于某棵树,该树的最大快乐值
    1. 根节点员工来party,则最大快乐值为每个子树根节点员工不来情况下的最大快乐值相加之和。
    2. 根节点员工不来party,则最大快乐值为MAX(a子树根节点来,a子树根节点不来) + MAX(b子树根节点来,b子树根节点不来) + … + MAX(n子树根节点来,n子树根节点不来)
class Solution {
    public static class Employee {
        public int happy; //这名员工可以带来的快乐值
        List<Employee> subordinates; //这名员工有哪些直接下级
    }

    public static int maxHappy(Employee boss) {
        Pair<Integer, Integer> bossPair = process(boss);
        return Math.max(bossPair.getKey(), bossPair.getValue());
    }

    /**
     * @param x 根节点员工
     * @return Pair<根节点来情况下该树最大快乐值,根节点不来情况下该树最大快乐值>
     */
    public static Pair<Integer, Integer> process(Employee x) {
        if (x.subordinates.isEmpty()) {
            // x是基层员工时
            return new Pair<>(x.happy, 0);
        }
        // x来时整棵树的最大快乐值,x不来时整棵树的最大快乐值
        int yes = x.happy, no = 0;
        for (Employee subordinate : x.subordinates) {
            Pair<Integer, Integer> subPair = process(subordinate);
            yes += subPair.getValue();
            no += Math.max(subPair.getKey(), subPair.getValue());
        }
        return new Pair<>(yes, no);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值