01背包例题

01背包题解

https://blog.csdn.net/qq_52934831/article/details/120102264?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163885949416780265422628%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=163885949416780265422628&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_v2~rank_v29-1-120102264.pc_v2_rank_blog_default&utm_term=DP&spm=1018.2226.3001.4450

Leetcode 416分割等和子集

地址

https://leetcode-cn.com/problems/partition-equal-subset-sum/

描述

在这里插入图片描述

思想

代码

class Solution {
    
    
public:
    bool canPartition(vector<int>& nums) {
    
    
        int n=nums.size(),m=0;
        //求出所有正整数的和
        for(auto x:nums) m+=x;
        //假如m是奇数,说明没办法对半分,直接return  false
        if(m%2==1) return false;
        //否则将数组对半分,每部分容量为m的一半
        else m/=2;
        vector<bool> f(m+1);
        f[0]=true;
        for(int i=1;i<nums.size();i++){
    
    
            int x=nums[i];
            for(int j=m;j>=x;j--){
    
    
                //dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]];
                f[j]=f[j]||f[j-x];
            }
        }
        return f[m];
    }
};

Leetcode 494 目标和(01背包变形,offset偏移量的运用)

地址

https://leetcode-cn.com/problems/target-sum/submissions/

描述

在这里插入图片描述

思想

题解地址
在这里插入图片描述

注释代码

//160 ms, 44.39%; 38.7 MB,7.40%
// y总讲解 二维解法:其中 f[i][j]中j的范围,设置为了[0, 2 * Offset]
class Solution {
    
    
public:
    int findTargetSumWays(vector<int>& nums, int S) {
    
    
        // 由于题目里说数组里总和最多只有1000,所以只能做[-1000,+1000],如果S不在这个范围就直接返回
        if (abs(S) > 1000) return 0; // S < -1000 || S > 1000

        int n = nums.size(), Offset = 1000; // 因为有负数,所以这里用一个偏移量,所有的j放到f里都要加上这个偏移量
        vector<vector<int>> f(n + 1, vector<int>(2 * Offset + 1));
        f[0][0 + Offset] = 1; // 选0个数,总和也是0的情况(因为在f数组里所以加上了一个偏移量Offset)

        for (int i = 1; i <= n; i ++ ) {
    
    
            // 本来 j范围是[-Offset, Offset],加上偏移量之后变为[-Offset + Offset, Offset + Offset], 即[0, 2* Offset]
            for (int j = 0; j <= 2 * Offset; j ++ ) {
    
     // f[i][j] 第二维下标 的范围要在 [0, 2*Offset] 之内
                // 注意:因为nums的下标是从0开始的,所以这里要用nums[i - 1]
                // a[i]取正数,0 <= j - nums[i - 1] <= 2*Offset, 因为 j~[0, 2*Offset]且nums[i]非负,所以肯定满足右半边不等式
                if (j - nums[i - 1] >= 0) // 只约束左半边不等式即可
                    f[i][j] += f[i - 1][j - nums[i - 1]];
                // a[i]取负数,0 <= j + nums[i - 1] <= 2*Offset, 因为 j~[0, 2*Offset]且nums[i]非负,所以肯定满足 左半边不等式
                if (j + nums[i - 1] <= 2 * Offset) // 只约束右半边不等式即可
                    f[i][j] += f[i - 1][j + nums[i - 1]];
            }
        }
        return f[n][S + Offset]; // 在前n个数里选,总和是S的方案数
    }
};

代码

class Solution {
    
    
public:
    int findTargetSumWays(vector<int>& nums, int s) {
    
    
        int n=nums.size(),offset=1000;
        //题目给出0 <= sum(nums[i]) <= 1000
        if(abs(s)>offset) return 0;//一定不可能达到
        vector<vector<int>> f(n+1,vector<int>(2*offset+1));
        f[0][0+offset]=1;
        for(int i=1;i<=n;i++){
    
    
            for(int j=0;j<=2*offset;j++){
    
    
                if(j-nums[i-1]>=0){
    
    
                    f[i][j]+=f[i-1][j-nums[i-1]];
                }
                if(j+nums[i-1]<=2*offset){
    
    
                    f[i][j]+=f[i-1][j+nums[i-1]];
                }

            }
        }
        return f[n][s+offset]; 在前n个数里选,总和是S的方案数
    }
};

猜你喜欢

转载自blog.csdn.net/qq_52934831/article/details/121770452