算法训练营day48_动态规划(3.16提前写)

算法训练营day48_动态规划(3.16提前写)

198.打家劫舍

这道题踩了个大坑,如果数组长度为1,就nums[0]一个数,不能初始f[1],会越界(因为f[1]用到了nums[1]);

土方法_背包思维

刚开始想到的就是二维背包,01背包,数组值为重量,价值,j最大就是sum值;

  • f(i,j)表示从前i个里取,重量不超过j的最大价值(价值不会超过j,因为每个物品重量==价值,最多只能放j重量的东西,价值最大等于j);输出的时候输出f(size()-1,sum)就行;
  • 要么取,要么不取;f(i,j)=max(f(i-1,j),f(i-2,j-w[i])+w[i]);
  • 从2开始循环,故要初始化0,1;
  • 01背包的循环套路;
class Solution {
public:
    int f[110][40010];

    int rob(vector<int>& nums) {
        if(nums.size()==1) return  nums[0];
        memset(f,0,sizeof f);
        int sum=0;
        for(int i=0;i<nums.size();i++) sum+=nums[i];
        for(int i=0;i<=sum;i++){
            f[0][i]=nums[0];
            f[1][i]=max(nums[0],nums[1]);
        }
        for(int i=2;i<nums.size();i++){
            for(int j=0;j<=sum;j++){
                f[i][j]=f[i-1][j];
                if(j>=nums[i]) f[i][j]=max(f[i][j],f[i-2][j-nums[i]]+nums[i]);
            }
        }
        return f[nums.size()-1][sum];
    }
};

正解_只需要一维

这道题对于重量没要求,所以与前面不同,这道题把重量这一维度直接去掉!

class Solution {
public:

    int rob(vector<int>& nums) {
        if (nums.size() == 1) return nums[0];
        vector<int> f(nums.size());
        f[0]=nums[0];
        f[1]=max(nums[0],nums[1]);

        for(int i=2;i<nums.size();i++){
            f[i]=max(f[i-1],f[i-2]+nums[i]);
        }
        return f[nums.size()-1];
    }
};

213.打家劫舍II

围成一圈,关键在于如何解环,转化成一排!

围成一圈之后,与之前不同的地方在于,如果0选了,n-1就选不了了;

分成两种情况:

  1. 0选了,1,n-1不选,考虑(2,n-1)左闭右开;
  2. 0没选,考虑(1,n)左闭右开;

越界问题搞了我好久。。。左闭右开,有一个元素是l==r-1,如果l>r-1说明一个元素都没,如[2,2)就是一个元素都没;

class Solution {
public:
    int dp(vector<int>& nums,int l,int r){
        if(l>r-1) return 0;
        if(l==r-1) return nums[l];
        vector<int> f(nums.size());
        f[l]=nums[l];
        f[l+1]=max(nums[l],nums[l+1]);
        for(int i=l+2;i<r;i++){
            f[i]=max(f[i-1],f[i-2]+nums[i]);
        }
        return f[r-1];
    }

    int rob(vector<int>& nums) {
        int n=nums.size();
        if (n==1) return nums[0];
        return max(nums[0]+dp(nums,2,n-1),dp(nums,1,n));
    }
};

337.打家劫舍III

树形dp,跟没有上司的舞会基本一样;只不过这里是链表构成的树形结构,平时我习惯数组构成树形结构;

这里的节点是T*,舞会节点是数字,这里节点值是t->val,舞会值是数组w[i];

下标是T*类型,故要开个哈希,f表示没偷,g表示偷了,也可以二维map,我这里不知道咋用哇(OK,查了一下, 就是map套map)

class Solution {
public:
    unordered_map<TreeNode*,map<int,int>> f;
    
    void dfs(TreeNode* t){
        f[t][1]=t->val;
        if(t->left!=NULL){
            dfs(t->left);
            f[t][0]+=max(f[t->left][0],f[t->left][1]);
            f[t][1]+=f[t->left][0];
        }
        if(t->right!=NULL){
            dfs(t->right);
            f[t][0]+=max(f[t->right][0],f[t->right][1]);
            f[t][1]+=f[t->right][0];
        }
    }

    int rob(TreeNode* root) {
        dfs(root);
        return max(f[root][0],f[root][1]);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值