【Leetcode动态规划--打家劫舍】198.打家劫舍 213.打家劫舍II 337.打家劫舍III

Leetcode198

1.问题描述

在这里插入图片描述

2.解决方案

代码sxl有详细过程,这里只做强调
1.确定 dp[i] 中 i 的含义也就是背包的容量,一开始想确定为就是所有金额的和sum,后来觉得多此一举,既然就选不选两种,然后就以nums的下标作为 i 的含义,并且将题目给的数组求长度作为背包的容量也是常见的
2.递推公式可以说比较巧妙,但也很好理解,就取不取两种取最大就好,一开始还想拿一个bool还确定取没取,后来发现不需要,交给前一个状态就好
3.初始化 dp[0] dp[1] 是递归入口,其他不初始化都可以,边界按含义就好!
4.提前判断少不了

class Solution {
public:
    int rob(vector<int>& nums) {
        //1.
        int len=nums.size();
        if(len==0) return 0;
        if(len==1) return nums[0];
        

        //2.
        vector<int> dp(len);
        dp[0]=nums[0];
        dp[1]=max(nums[0],nums[1]);

        //3.
        for(int i=2;i<len;i++){
            dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
        }

        //4.
        return dp[len-1];
    }
};

Java版本

class Solution {
    public int rob(int[] nums) {
        //1.
        int len = nums.length;
        int[] dp = new int[len];
        if(len==0) return 0;
        if(len==1) return nums[0];
        if(len==2) return Math.max(nums[0], nums[1]);
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0], nums[1]);
        //2.
        for(int i=2;i<len;i++){
            dp[i] = Math.max(dp[i-1], dp[i-2]+nums[i]);
        }
        return dp[len-1];
    }
}




Leetcode213

1.问题描述

在这里插入图片描述

2.解决方案

代码sxl上面有详细过程,这只做强调
1.由于题目特殊性,无法直接动态规划,所以我们要通过分析然后转化成198那种普通的打家劫社,于是既然首尾不能同时出现,那就分情况讨论,一种不出现首,一种不出现尾,然后一合大的就是结果,分情况后和198一摸一样
2.可能是边上课边写的代码,一个很粗心的错误如下,就是调用simpleRob函数后,如果定义了len=end-start+1,那么start还是对应nums,你这开辟了一个新的,dp的下标和nums的下标就不一致了

//int len=end-start+1;
int len=nums.size();

//2.
 vector<int> dp(len);
class Solution {
public:
    int rob(vector<int>& nums) {
        //1.
        int len=nums.size();
        if(len==0) return 0;
        if(len==1) return nums.at(0);

        //2.闭区间 [start,end]
        int result1=simpleROb(nums,0,len-2);
        int result2=simpleROb(nums,1,len-1);

        //3.
        return max(result1,result2);
    }
    //和198一样的思路
    int simpleROb(vector<int>& nums,int start,int end){
        //1.
        if(start==end) return nums.at(start);
        //int len=end-start+1;
        int len=nums.size();

        //2.
        vector<int> dp(len);
        dp[start]=nums.at(start);
        dp[start+1]=max(nums.at(start),nums.at(start+1));

        //3.
        for(int i=start+2;i<=end;i++){
            dp[i]=max(dp[i-1],dp[i-2]+nums.at(i));
        }

        //4.
        return dp[end];
    }
};

Java版本,注意点:
1.只有当len==4的时候才需要进入dp,其他情况答案都是固定的
2.在dp中,有一个映射的关系 dp[0]对应的是nums[left],所以这个要关注

class Solution {
    public int rob(int[] nums) {
        int len = nums.length;
        if(len==0) return 0;
        if(len==1) return nums[0];
        if(len==2) return Math.max(nums[0], nums[1]);
        if(len==3) return Math.max(nums[0], Math.max(nums[1], nums[2]));

        int ans1 = robMax(nums, 0, len-2);
        int ans2 = robMax(nums, 1, len-1);

        return Math.max(ans1, ans2);
    }
    public int robMax(int[] nums, int left, int right) {
        //1.
        //0,1,2 len>=3
        int len = right-left+1;
        int[] dp = new int[len];
        dp[0] = nums[left];
        dp[1] = Math.max(nums[left], nums[left+1]);
        //2.
        for(int i=2;i<len;i++){
            dp[i] = Math.max(dp[i-1], dp[i-2]+nums[left+i]);
        }
        return dp[len-1];
    }
}




Leetcode337

1.问题描述

在这里插入图片描述

2.解决方案

代码sxl上面有详细解答,这里制作强调
1.这个题是递归三部曲和动态规划五部曲的结合
2.暴力递归和记忆化递推都是实时计算,没有做记录
3.使用一个二元组对应每一个节点的状态,即不偷和偷的最大值,并且遍历的顺序也是后序遍历,也就是说计算当前节点的二元组时它的左右儿子都已经计算过了,所以也是自底向上,很符合动态规划的思想!
4.至于递推比较简单
5.初始化即叶节点的左右儿子状态都是 {0,0 }

class Solution {
public:
    vector<int> treeRob(TreeNode* cur){
        //1.递归出口
        if(cur== nullptr) return vector<int>{0,0};

        //2.
        vector<int> left=treeRob(cur->left);
        vector<int> right=treeRob(cur->right);

        //3.动态规划状态转移
        int notROb=max(left[0],left[1])+max(right[0],right[1]);
        int ROb=cur->val+left[0]+right[0];

        //4.
        return vector<int>{notROb,ROb};
    }
    int rob(TreeNode* root) {
        //ans[0]不偷 ans[1]偷
        vector<int> ans=treeRob(root);
        return max(ans[0],ans[1]);
    }
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值