力扣337. 打家劫舍 III(树形动态规划)

力扣337. 打家劫舍 III(树形动态规划)

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

示例 1:                                                                                                          示例 2:

           

 

树形动态规划:

有两点思路需要重点注意:

  1. 在设计状态的时候,在后面加一维,消除后效性,打家劫舍第 1 题,股票系列问题 6 个问题,都是这样的思路;
  2. 树的问题,很多时候采用后序遍历:我们的逻辑是子结点陆续汇报信息给父结点,一层一层向上汇报,最后在根结点汇总值

每个节点可选择偷或者不偷两种状态,根据题目意思,相连节点不能一起偷

  • 当前节点选择偷时,那么两个孩子节点就不能选择偷了
  • 当前节点选择不偷时,两个孩子节点只需要拿最多的钱出来就行(两个孩子节点偷不偷没关系)

我们使用一个大小为 2 的数组来表示 int[] res = new int[2] 0 代表不偷,1 代表偷

任何一个节点能偷到的最大钱的状态可以定义为:

  • 当前节点选择不偷:当前节点能偷到的最大钱数 = 左孩子能偷到的钱 + 右孩子能偷到的钱
  • 当前节点选择偷:当前节点能偷到的最大钱数 = 左孩子选择自己不偷时能得到的钱 + 右孩子选择不偷时能得到的钱 + 当前节点的钱数

关键:当前结点「偷」或者「不偷」决定了孩子结点偷或者不偷,把这一点设计成状态,放在第 2 维,这一步叫「消除后效性」,这一点技巧非常常见

//
//  main.cpp
//  rob3
//
//  Created by MXQ on 2020/10/20.
//
#include <iostream>
#include<vector>
using namespace std;
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

class Solution {
public:
    int rob(TreeNode* root) {
        vector<int> result(2,0);
        robnode(root,result);
        return max(result[0], result[1]);
    }
    void robnode(TreeNode* root,vector<int> &result)
    {
        if (root==nullptr) {
            return;
        }
        //遍历一次
        vector<int> leftresult(2,0);
        vector<int> rightresult(2,0);
        robnode(root->left,leftresult);
        robnode(root->right,rightresult);
        result[0]=max(leftresult[0],leftresult[1])+max(rightresult[0],rightresult[1]);
        result[1]=leftresult[0]+rightresult[0]+root->val;
    }
};


int main(int argc, const char * argv[]) {
    // insert code here...
    TreeNode p[6] = {3,4,5,1,3,1};
    p[0].left=&p[1];p[0].right=&p[2];
    p[1].left=&p[3];p[1].right=&p[4];
    p[2].right=&p[5];
    Solution s;
    auto result=s.rob(p);
    std::cout <<result<<endl;
    std::cout << "Hello, World!\n";
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值