打家劫舍 DP解法

打家劫舍

顺序偷盗:
  1. 我考虑的是偷到 i 家,钱的最大值;我固定了 i 次的必须偷到,那上一次投就是i-2或者i-3家,因为i-4家可能往后再偷i-2家。
class Solution {
public:
    int rob(vector<int>& nums) {
        int pre1sum=0,pre2sum=0,pre3sum=0;
        int n =nums.size(),sum=0;
        for(int i=0;i<n;i++){
            int temp=max(pre2sum,pre1sum) + nums[i];
            pre1sum = pre2sum;
            pre2sum = pre3sum;
            pre3sum = temp;
        }
        return max(pre3sum,pre2sum);
    }
};
  1. 简单的考虑是路过i家,钱的最大值,这样sum结果就是最后一家的值;两种情况,num[i]+f(i-2)或者f(2)
    dp的方向要考虑重点是存储结果的位置
class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.empty()) return 0;
        int n =nums.size();
        if(n == 1) return nums[0];
        int pre1sum=nums[0],pre2sum=max(nums[0],nums[1]);
        for(int i=2;i<n;i++){
            int temp=max(pre2sum,pre1sum + nums[i]);
            pre1sum = pre2sum;
            pre2sum = temp;
        }
        return pre2sum;
    }
};
循环盗窃
  1. 仔细考虑,其实只有一种区别,在0位置取了之后,在end-1位置不能取了。分类讨论,两种情况,取0位置和不取0位置dp。
    之前一直考虑把取到了0位置的所有分支都标记上,用pair表示sum,但是dp中交换次数很多,而且dp考虑单独特定情况不容易,最后还是启动两次。
class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.empty()) return 0;
        int n =nums.size();
        if(n < 4) return *std::max_element(nums.begin(),nums.end());
        return max(helper(nums,0,n-1),helper(nums,1,n));
    }
    int helper(vector<int>& nums,int start,int end){

        int pre1sum=nums[start],pre2sum=max(nums[start],nums[start+1]);
        for(int i=start+2;i<end;i++){
            int temp=max(pre2sum,pre1sum + nums[i]);
            pre1sum = pre2sum;
            pre2sum = temp;
        }
        return pre2sum; 
    }
};
二叉树盗窃
  1. 考虑dp两种想法
    一种是自顶向下,看每步之后的操作,比如下一步抢或者不抢,然后取Max,经常用到递归函数。但是每次到这一步的前置情况很多,存在很多重叠子问题,需要用备忘录剪枝
    一种是自底向上,只考虑单个状态的最大值情况,考虑什么情况能到这一步,更接近结果
  2. 前面两都是用更难想但是更快的自底向上,树形不好想前置情况(因为树不好找父节点),我先考虑下一步的dp,其实更像带备忘录的纯递归方法
class Solution {
public:
    int rob(TreeNode* root) {
        if(root == nullptr) return 0;
					 // 到次节点的前置情况很多,用备忘录去重
        if(memo.count(root)) return memo[root];
					
        int do_it =root->val +( root->left==nullptr?0:rob(root->left->left)+rob(root->left->right))
            +( root->right==nullptr?0:rob(root->right->left)+rob(root->right->right));    

        int not_do =rob(root->left)+rob(root->right);
        int res = max(do_it,not_do);
        memo[root] =res;
        return res;
    }
private:
    unordered_map<TreeNode*,int> memo;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值