ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

337.打家劫舍|||

2020-05-06 18:08:04  阅读:296  来源: 互联网

标签:right TreeNode 337 节点 打家劫舍 root rob left


题目描述:

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

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

 

思想:

思想1:暴力递归 - 最优子结构

  4 个孙子偷的钱 + 爷爷的钱 VS 两个儿子偷的钱 哪个组合钱多,就当做当前节点能偷的最大钱数。这就是动态规划里面的最优子结构

思想2:记忆化 - 解决重复子问题

  针对解法一种速度太慢的问题,经过分析其实现,发现爷爷在计算自己能偷多少钱的时候,同时计算了 4 个孙子能偷多少钱,也计算了 2 个儿子能偷多少钱。这样在儿子当爷爷时,就会产生重复计算一遍孙子节点。

  针对重复子问题进行优化,我们在做斐波那契数列时,使用的优化方案是记忆化,但是之前的问题都是使用数组解决的,把每次计算的结果都存起来,下次如果再来计算,就从缓存中取,不再计算了,这样就保证每个数字只计算一次。
由于二叉树不适合拿数组当缓存,我们这次使用哈希表来存储结果,TreeNode 当做 key,能偷的钱当做 value

思想3:

换一种办法来定义此问题,每个节点可选择偷或者不偷两种状态,根据题目意思,相连节点不能一起偷

当前节点选择偷时,那么两个孩子节点就不能选择偷了
当前节点选择不偷时,两个孩子节点只需要拿最多的钱出来就行(两个孩子节点偷不偷没关系)
使用一个大小为 2 的数组来表示 vector<int> res(2)  0 代表不偷,1 代表偷
任何一个节点能偷到的最大钱的状态可以定义为

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

 

参考:https://leetcode-cn.com/problems/house-robber-iii/solution/san-chong-fang-fa-jie-jue-shu-xing-dong-tai-gui-hu/

 

代码:

/**
 * Definition for a binary tree node.
 * 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> res = rob_func(root);
        return max(res[0],res[1]);
    }
    vector<int> rob_func(TreeNode* p){
        vector<int> tmp(2);
        if(p==NULL)
            return tmp;
        vector<int> left(2),right(2); 
        if(p->left !=NULL)
            left = rob_func(p->left);
        if(p->right !=NULL)
            right = rob_func(p->right);
        tmp[0] = max(left[0],left[1]) + max(right[0],right[1]);
        tmp[1] = left[0] + right[0] + p->val;
        return tmp;
    }
};

效率较低

改进版:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    /*用unordered_map保存每个节点的最高金额*/
    int rob_dp(TreeNode* root,unordered_map<TreeNode*,int>&info)
    {
        if (root==NULL)
        {
            return 0;
        }
        if (info.find(root)!=info.end())  //如果该节点已经计算过,则不用再重复计算
        {
            return info[root];
        }
        int money=root->val;
        if (root->left!=NULL)
        {
            money+=rob_dp(root->left->left,info)+rob_dp(root->left->right,info);
        }
        if (root->right!=NULL)
        {
            money+=rob_dp(root->right->left,info)+rob_dp(root->right->right,info);
        }
        int result=max(money,rob_dp(root->left,info)+rob_dp(root->right,info));
        info.insert(make_pair(root,result));
        return result;
    }
    int rob(TreeNode* root) 
    {
        unordered_map<TreeNode*,int>temp;
        return rob_dp(root,temp);
    }
};

 

标签:right,TreeNode,337,节点,打家劫舍,root,rob,left
来源: https://www.cnblogs.com/thefatcat/p/12837951.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有