第九周:( LeetCode337) House Robber III(c++)

本周上课的重点依然为动态规划,主要讲树状dp、状态压缩dp、Floyd-Warshall算法。这是一道典型的树状dp的题,难度为Medium。

原题:
The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the “root.” Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that “all houses in this place forms a binary tree”. It will automatically contact the police if two directly-linked houses were broken into on the same night.
Determine the maximum amount of money the thief can rob tonight without alerting the police.

Example 1:

     3
    / \
   2   3
    \   \ 
     3   1

Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.

Example 2:

     3
    / \
   4   5
  / \   \ 
 1   3   1

Maximum amount of money the thief can rob = 4 + 5 = 9.

思路:题目的大意是,在一棵树中,连接一条边的两个点至多只能有一个点能被偷窃,如果两个点同时被偷窃,就会报警。显然,这是一道几乎裸的树状dp,可以用树的递归遍历来做。以某一顶点为根,其所在的树能偷窃的最大值,就是该问题的子问题。一个父节点所在的树能偷窃的最大值,肯定与其左右子树能偷窃的最大值有关,这就是动态规划!关键是到底有什么关系呢?求一个父节点所在的树能偷窃的最大值,分为两种情况:一是,父节点本身包括,这时左右孩子节点肯定都不包括;二是,父节点本身不包括,这时左右孩子节点可包括可不包括。这两种情况的最大值就是我们要求的结果。因此,对于某个节点,我们只需维护该节点的两个值。用include保存包括该节点的情况下以该节点为根的树能偷窃的最大值;用not_include保存不包括该节点的情况下以该节点为根的树能偷窃的最大值。某节点include值=lefttree.not_include+righttree.not_include+该节点val;某节点not_include值=max(lefttree.not_include,lefttree.include)+max(righttree.not_include,righttree.include)。以上其实就是树状dp的状态转移方程。

代码:9ms通过

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
//保存以某个节点为根的树所能偷窃的最大值
//include表示在包含该节点的情况下的最大值,not_include表示在不包含该节点的情况下的最大值
struct result
 {
    int include,not_include;
 }; 

class Solution {
    result find(TreeNode* root){
        result res;
        //节点为叶子结点的情况
        if(!root){
            res.include=0;
            res.not_include=0;
            return res;
        }else{
            //非叶子结点的情况
            result ltree,rtree;
            ltree=find(root->left);
            rtree=find(root->right);
            res.include=ltree.not_include+rtree.not_include+root->val;
            res.not_include=max(ltree.not_include,ltree.include)+max(rtree.not_include,rtree.include);
            return res;
        }
    }

public:
    int rob(TreeNode* root) {
        result res;
        res=find(root);
        return max(res.include,res.not_include);
    }
};

ps:本题还要注意递归函数的效率问题。以下代码算法思路和上述ac代码是完全一样的,仅仅因为递归函数写得不够精简的问题,就超时了!代码如下:

struct result
 {
    int include,not_include;
 }; 

class Solution {
public:
    result find(TreeNode* root){
        result res;
        if(!root){
            res.include=0;
            res.not_include=0;
            return res;
        }else{
            //每层递归都包含四个子函数,递归规模指数增长!
            int left_not=find(root->left).not_include;
            int left_in=find(root->left).include;
            int right_not=find(root->right).not_include;
            int right_in=find(root->right).include;
            res.include=left_not+right_not+root->val;
            res.not_include=max(left_not,left_in)+max(right_not,right_in);
            return res;
        }
    }

    int rob(TreeNode* root) {
        result res;
        res=find(root);
        return max(res.include,res.not_include);
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值