da42:背包问题|● 416. 分割等和子集

题目链接:416. 分割等和子集

1.代码

class Solution {
public:
    bool canPartition(vector& nums) {
        int sum = 0;
        for (int i: nums) {
            sum += i;
        }
        if (sum % 2 != 0) return false;
        sum /= 2;
         vectorf(sum + 1);
         for (int i = 0; i < nums.size(); i++) {
             for (int j = sum; j >= nums[i]; j--) {
                 f[j] = max(f[j], f[j - nums[i]] + nums[i]);
             }
         }
         if (f[sum] == sum) return true;
         else return false;
    }
};

2.思路

题目的意思是看下可以把这个数组分成两个部分,这两部分相加会相等吗?如果相等返回false,否则返回true,所以只要有一部分数组相加等于nums数组的总和的一半就行了

由此就能把问题转化成从n个数据中找到数据相加等于sum/2的组合,可以用回溯法

3.回溯法(超时)

class Solution {
public:
  int res;
  int flag = 0;
    void backtracking(int sum, vector& nums, int startindex) {
        if (res > sum || flag == 1) return;
        if (res == sum) flag = 1;
        for (int i = startindex; i < nums.size(); i++) {
            res += nums[i];
            backtracking(sum, nums, i + 1);
            res -= nums[i];
        }
   }
    bool canPartition(vector& nums) {
        int sum = 0;
        for (int i: nums) {
            sum += i;
        }     
        if (sum % 2 != 0) return false;  
        sum = sum / 2;
        backtracking(sum, nums, 0);
        if (flag == 1) return true;
        else return false;
    }
};

4.动规五部曲

还可以转化为求背包大小为sum/2的可以装入的最大价值,最后只要判断最后一个背包的价值等于不等于sum/2就知道结果了,所以可以使用01背包

1.确定dp数组和其下标的含义

dp[j]代表大小为j的背包可以装入的最大价值,这里的背包空间和价值都是sum

2.确定递推数组

01背包,在每一个问题中,可以转化为选还是不选当前的物品,这里就是选不选这个值,由此可以得出

不选f[i][j] = f[i - 1][j], 选f[i -1] [j - nums[i]] + nums[i], 可以转化成一维数组,把i去掉就行了

选择第i个物品代表一定要选他,代表需要留足够的空间来选他,所以需要减去所需要占的空间

 3.初始化

初始化就是当小于该体积时就为0,不用变化,我们在先后顺序那里再判断

4.遍历顺序

先遍历物品,不断加每一个物品, 第二层循环是递推每一个不同大小的背包

这里是反的顺序遍历,因为反的遍历可以避免重复加上该物品(数据),逆序就能避免了,自己可以进行推导

背包大小小于物品的大小时就转不下就不需要遍历了,可以在for循环中判断

5.递推模拟dp数组

模拟

你可能感兴趣的:(代码随想录一刷,leetcode,算法,c++,蓝桥杯,动态规划)