[动态规划]小总结

动态规划
1.定义 ?
2.基本实现模式:
①先设置一个一维数组 int dp[n]/二维数组 int dp[n][n]
(什么时候设置一维数组/什么时候设置二维数组):取决于你的dp[i]具有什么意义 难点
做题总结:二维数组多涉及到位置关系,如坐标(i,j)用dp[i][j]表示
②找到dp中每一项与上一项或者下一项之间的关系:写出关系表达式 难点
③找到基准条件:如dp[0] dp[1] dp[2]
3.题型总结
first. House Robber 198 https://leetcode-cn.com/problems/house-robber/
官方题解

#include <algorithm>
class Solution {
public:
    int rob(vector<int>& nums) {
         int n=nums.size();//n houses
         int dp[n+1];// dp[i] means visit the former ith house you can get the max money
         if(n==1) return nums[0];
         else if(n==2) return max(nums[0],nums[1]); 
         dp[0]=nums[0];
         dp[1]=max(nums[0],nums[1]);
         for(int i=2;i<n;i++)
            dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
         return dp[n-1];
    }
};

官方题解中没有想到的点是:
dp[i]的意义是前i所房子所能得到的最大金额
所以等到最后一间房子,假设其为第k间房子的时候,就只有两种选择:要么是选择前k-1间房子所得到的最大金额,要么是选择前k-2间房子+第k间房子所得到的最大金额。
代码理解即为: max(dp[k-2],dp[k-3]+nums[k-1])
注意代码实现的时候,第k间房子对应的Index为k-1

MyCode

#include <algorithm>
class Solution {
public:
    int rob(vector<int>& nums) {
         int n=nums.size();//n houses
         int dp[n+1];//dp[i] means visit the ith house you can get the max money
         if(n==1) return nums[0];
         else if(n==2) return max(nums[0],nums[1]);
         dp[0]=nums[0];
         dp[1]=nums[1];
         dp[2]=dp[0]+nums[2];
         for(int i=3;i<n;i++)
           dp[i]=max(dp[i-2]+nums[i],dp[i-3]+nums[i]);
         int ans=0;
          for(int i=0;i<n;i++)
            if(dp[i]>ans)
               ans=dp[i];
           return ans;
    }
};

主要思路
当时构思的是dp[i]的意义是选择抢第i间房子时能得到的最大收益
所以每个房子都会有对应自己的dp[i],所以最后需要寻找dp[n]中的最大值才能得到答案。

second. Delete and Earn 740 https://leetcode-cn.com/problems/delete-and-earn/
官方题解

class Solution {
private:
    int rob(vector<int> &nums) {
        int size = nums.size();
        int first = nums[0], second = max(nums[0], nums[1]);
        for (int i = 2; i < size; i++) {
            int temp = second;
            second = max(first + nums[i], second);
            first = temp;
        }
        return second;
    }

public:
    int deleteAndEarn(vector<int> &nums) {
        int maxVal = 0;
        for (int val : nums) {
            maxVal = max(maxVal, val); //这里没看懂??
        }
        vector<int> sum(maxVal + 1); //创建一个sum数组
        for (int val : nums) { //foreach语句,迭代数组全部元素
            sum[val] += val; //给sum数组元素赋初值
        }
        return rob(sum);
    }
};

官方题解主要思路
(部分语句没看懂)

MyCode

#include <algorithm>
class Solution {
public:
    int deleteAndEarn(vector<int>& nums) {
        vector<int> sum(1001,1);//1 - 1000 initial 1 only 1 means that the number of the number is 1
        int n=nums.size();// 字符个数
        if(n==1) return nums[0];
        if(n==2) 
        {
            if(nums[0]+1==nums[1] || nums[0]-1==nums[1])
              return max(nums[0],nums[1]);
            else return nums[0]+nums[1];
        }
        vector<int> norepeat(n);
        vector<int> ::iterator it1=nums.begin();
        vector<int> ::iterator it2=nums.end();
        sort(it1,it2);
        int t=0;
        for(int i=1;i<n;i++)
        {
            if(nums[i]==nums[i-1])//前面跟后面对比
                {
                    sum[nums[i]]++;
                    if(sum[nums[i]]==2) norepeat[t++]=nums[i];
                }
            if(sum[nums[i-1]]==1) norepeat[t++]=nums[i-1];   
        }
         if(nums[n-1]!=nums[n-2]) norepeat[t++]=nums[n-1];
        for(int i=0;i<t;i++)
            cout << norepeat[i]<<" sum:"<<sum[norepeat[i]]<<endl;
        int dp[n];//dp[i] measn 消除前i个可以得到的最大数
        dp[0]=norepeat[0]*sum[norepeat[0]];
        dp[1]=(norepeat[1]-1==norepeat[0])?max(norepeat[1]*sum[norepeat[1]],dp[0]):dp[0]+norepeat[1]*sum[norepeat[1]];
        for(int i=2;i<norepeat.size();i++)
        {
        dp[i]=(norepeat[i]-1==norepeat[i-1])?max(norepeat[i]*sum[norepeat[i]]+dp[i-2],dp[i-1]):dp[i-1]+norepeat[i]*sum[norepeat[i]];
        cout << dp[i]<<endl;
        }
        return dp[norepeat.size()-1];

    }
};

主要思路
1.dp[i]的意义是选择前i个数字能够获得的最大收益
2.做这道题需要解决的问题是:

  • 重复数字的解决–如[2,2,3,3,3] 轮到前3个如果单一考虑前i个数字能够获得的最大收益,则必然会抛弃第一个3而选择 第1 2 个已经组成的4
    出错:片面思考
    解决方法 (参考了官方题解) 设置一个数组sum,记录每个对应的nums[i]出现的次数,初始值为1,若出现多个则不断sum[nums[i]]++;最后比较的时候应该比较nums[i]*sum[nums[i]]而非单一的nums[i]
    进一步探讨 同时我也选择构建一个新的数组norepeat企图消除相同重复的数字,但后来思考这里大概是可以优化的
    理论上可以由第一个出现的重复数字决定了dp[i] (假设第一个出现的重复数字的Index为i) 则随后若有相同的即 if(nums[i+1]==nums[i]) dp[i+1]=dp[i];
    【尚未尝试,之后会尝试优化一下】
  • 乱序问题:因为题目讨论的是i-1 与i+1 即为相邻位置,然而案例给出的数据全都是乱序,所以想到了用sort先行对nums数组进行排序

与第一道题目的相似之处
1.同样是存在邻居困境问题,题目是这个意思,但第二道题需要进行处理一下才能转化为第一道题

待解决:10.12.21

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值