day-43 代码随想录算法训练营(19) 动态规划 part 05

1049.最后一块石头的重量||(有点感觉了)

分析:
  • 只有石头不相等时,才会剩下石头,所以相等的部分会两两抵消;
  • 所以最后一块石头一定是两两抵消的结果,总和-抵消*2=最后一块石头
  • 转换为背包问题:容量=总和/2 看最多能装多少,装满即完全抵消
思路:
  • 1.dp存储:当容量为j时,装的最大重量dp[j]
  • 2.dp [ j ] =max(dp [ j ],dp [ j - stones [ i ] ] + stones [ i ] ) 
  • 3.初始化:全为0
  • 4.遍历顺序:外层遍历石头,内层遍历背包容量
class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
        int total=0;
        for(auto it:stones) total+=it;
        int target=total/2;
        vector<int>dp(total+1,0);
        for(int i=0;i<stones.size();++i){
            for(int j=target;j>=stones[i];--j){
                dp[j]=max(dp[j],dp[j-stones[i]]+stones[i]);
               
            }
        }
        return total-2*dp[target];

    }
};

494.目标和

分析:
  • 正数值add  负数值sub  总和sum
  • add-sub=target -> add-(sum-add)=target -> add=(target+sum)/2
  • 得出需要达到的正数值,转换为背包问题:装满add有几种方法
思路:
  • 1.dp存储:值为 j 时有dop[j]种方法装满
  • 2.dp[j]+=dp[j-nums[i]]  只要装入nums[i]刚好装满的方法都可行
  • 3.初始化:dp[0]=1 不装就是一种方法
  • 4.遍历顺序:外层遍历元素  内层遍历背包容量
class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int target) {
        int total=0;
        for(auto it:nums) total+=it;
        if(abs(target)>total) return 0;
        if((target+total)%2==1) return 0;//如果为奇数,说明add无法取整,无法得出结果
        int add=(target+total)/2;
        vector<int>dp(add+1,0);
        dp[0]=1;
        for(int i=0;i<nums.size();i++){
            for(int j=add;j>=nums[i];--j){
                dp[j]+=dp[j-nums[i]];
            }
        }
        return dp[add];
    }
};

474.一和零

分析:
  • 分析:在满足0和1个数的同时,尽量多的装字符串
  • 转化为背包问题:二维容量:zeroNum oneNum 的容量下,最多能装多少物品
思路:
  • 1.dp存储:当可以装0为i个,1为j个时,最多可以装dp[i][j]个字符串
  • 2.dp[i][j]=max(dp[i][j],dp[i-zeroNum][j-oneNum]+1);  装入当前值后,总数+1
  • 3.初始化:全为0
  • 4.遍历顺序:外层遍历字符串数组,内层两个for循环进行字符容量遍历
class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        vector<vector<int>>dp(m+1,vector<int>(n+1,0));
        for(int i=0;i<strs.size();i++){
            int oneNum=0,zeroNum=0;
            for(char it:strs[i]){//记录当前字符0和1的数量
                if(it=='0') zeroNum++;
                else oneNum++;
            }
            
            for(int j=m;j>=zeroNum;--j){//二维装填
                for(int k=n;k>=oneNum;--k){
                    dp[j][k]=max(dp[j][k],dp[j-zeroNum][k-oneNum]+1);
                }
            }
        }
        return dp[m][n];
        
    }
};

518.零钱兑换 ||(坐牢)

分析:完全背包
思路:
  • 1.dp存储:价值 j 时,可以装的方法有 dp[j] 种
  • 2.dp[j]+=dp[j-coins[i]]
  • 3.初始化:dp[0]=1
  • 4.遍历顺序:外层遍历硬币,内层遍历容量
class Solution {
public:
    int change(int amount, vector<int>& coins) {
        int n=coins.size();
        vector<int>dp(amount+1);
        dp[0]=1;
        for(int i=0;i<n;i++){
            for(int j=coins[i];j<=amount;j++){
                cout<<dp[j]<<endl;
                dp[j]+=dp[j-coins[i]];
            }
        }
        return dp[amount];
        
    }
};

377.组合总和IV(微微坐牢啊)

思路:
  • 1.dp存储:和为 j 时,组成这个和的种数为 dp[j]
  • 2.dp[j]+=dp[j-nums[i]];
  • 3.初始化:dp[0]=1
  • 4.遍历顺序:外层遍历容量  内层遍历元素

本题需要的是排列:所以先遍历容量(背包)

class Solution {
public:
    int combinationSum4(vector<int>& nums, int target) {
        vector<int>dp(target+1,0);
        dp[0]=1;
        for(int i=0;i<=target;i++){
            for(int j=0;j<nums.size();j++){
                if(i-nums[j]>=0 && dp[i]<=INT_MAX-dp[i-nums[j]])
                    dp[i]+=dp[i-nums[j]];
            }
        }
        return dp[target];
    }
};

猜你喜欢

转载自blog.csdn.net/Ricardo_XIAOHAO/article/details/132707400