[Leetcode] 416. 分割等和子集、1049. 最后一块石头的重量 II、494. 目标和、474. 一和零

内容:今天复习下dp数组中的背包问题

分割等和子集 - 能否装满

最后一块石头 - 尽可能装满

目标和 - 有多少种方法装

一和零 - 装满背包有多少个物品

416. 分割等和子集

10背包:用/不用;有容量;有价值

dp[j] : 容量为j,最大价值为dp[j]

        重量和价值等价

dp[target] == target 属于装满

target = sum/2

递推公式:dp[j] = max(dp[j], dp[j-weight[i]]+value[i])

        状态转移方程:只有放和不放两种情况

dp[j] = max(dp[j], dp[j-nums[i]]+nums[i])

初始化:dp[0] = 0

其他(非零下标)=0

class Solution {
public:
    bool canPartition(vector& nums) {
        int sum = 0;
        for(int num:nums) {
            sum += num;
        }
        if(sum%2!=0) {
            return false;
        }
        int target = sum/2;
        int size = 200*100/2 + 1;
        vector dp(size, 0);
        for(int i=0; i=nums[i]; --j) {
                dp[j] = max(dp[j], dp[j-nums[i]]+nums[i]);
            }
        }
        return dp[target] == target;

    }
};

1049. 最后一块石头的重量 II

class Solution {
public:
    int lastStoneWeightII(vector& stones) {
        int size = 30*100/2 + 1;
        vector dp(size, 0);
        int sum = 0;
        for(int stone:stones) {
            sum += stone;
        }
        int target = sum/2;
        for(int i=0; i=stones[i]; --j) {
                dp[j] = max(dp[j], dp[j-stones[i]]+stones[i]);
            }
        }
        return sum-2*dp[target];
    }
};

494. 目标和

假设加法的总和为x,那么减法对应的总和就是sum - x。

所以我们要求的是 x - (sum - x) = target

x = (target + sum) / 2

有多少种方法装满

dp[j]:装满背包容量为j,有dp[j]种方法

class Solution {
public:
    int findTargetSumWays(vector& nums, int target) {
        int sum = 0;
        for(int num:nums) {
            sum += num;
        }
        if(abs(target)>sum) {
            return 0;
        }
        if((target+sum)%2 != 0) {
            return 0;
        }

        int bagSize = (target+sum) /2;
        vector dp(bagSize+1, 0);
        dp[0] = 1;
        for(int i=0; i=nums[i]; --j) {
                dp[j] += dp[j-nums[i]];
            }
        }
        return dp[bagSize];
    }
};

474. 一和零

m个0,n个1的容器

装满这个背包(二维)最多几个物品

背包两个维度:dp[i][j] - i个0,j个1,最多装dp[i][j] 个物品

        三个变量

递推公式:dp[j] = max(dp[j], dp[j-weight[i]]+value[i])

重量:x个0,y个1 (用两个维度来形容物品重量)

最大容量:m个0,n个1

物品数量:dp[i-x][j-y] + 1

dp[i][j] = max(dp[i][j], dp[i-x][j-y] + 1)

dp[0][0] = 0

非零下标 = 0

先物品后重量

class Solution {
public:
    int findMaxForm(vector& strs, int m, int n) {
        vector> dp(m+1, vector (n+1, 0));
        for(string str:strs) {
            int zeroNum =0;
            int oneNum = 0;
            for(char c:str) {
                if(c=='0') zeroNum++;
                else oneNum++;
            }
            for(int i=m; i>=zeroNum; --i) {
                for(int j=n; j>=oneNum; --j) {
                    dp[i][j] = max(dp[i][j], dp[i-zeroNum][j-oneNum]+1);
                }
            }
        }
        return dp[m][n];

    }
};

你可能感兴趣的:(leetcode,算法,职场和发展)