• LeetCode416. 分割等和子集


    题目

    分析

    两个子集和相等,转化为找到所有元素总和一半的集合。注意不能回溯,因为时间复杂度为O(2N)会超时。可以将此问题看成0-1背包问题。背包容量为sum / 2。如果总和一半为奇数,那么不可分成两个相同总和的子集。在此问题种物品的重量和价值为数字本身的数值。设dp[i][j]为从0-i中选取不超过容量j 的最大价值。动态转移方程就为01背包的转移方程。每个物品价值为正整数,所以dp数组初始化为0。若有负数,则应初始化为负无穷。

    代码

     1 class Solution {
     2 public:
     3     bool canPartition(vector<int>& nums) {
     4         int sum = 0;
     5         for(auto num:nums){
     6             sum += num;
     7         }
     8         if(sum % 2) return false;  //和为奇数必然不能分成两个和相同的子集
     9         sum /= 2;
    10         vector<vector<int>> dp(nums.size(),vector<int>(sum+1,0));
    11         //int dp[nums.size()][sum+1];
    12         //memset(dp,0,sizeof(dp));
    13         for(int j = 0;j <= sum;j++){  //初始化
    14             if(nums[0] <= j) dp[0][j] = nums[0];
    15         }
    16           
    17         for(int i = 1;i <nums.size();i++){
    18             for(int j = 0;j <= sum;j++){
    19                 if( j < nums[i]) dp[i][j] = dp[i-1][j];
    20                 else dp[i][j] = max(dp[i-1][j],dp[i-1][j-nums[i]] + nums[i]);
    21             }
    22         }
    23         if(sum == dp[nums.size()-1][sum]) return true;
    24         else return false;
    25     }
    26 };

    关于二维数组初始化可以memset,也可用vector,10—12行

    优化

    使用滚动数组将二维转换为一维。dp[i][j] = max(dp[i-1][j],dp[i-1][j-nums[i]] + nums[i])中上一层(i-1层)可以直接拷贝到 i 层上,这样就变成了dp[i][j] = max(dp[i][j],dp[i][j-nums[i]] + nums[i]),就可以把 第一维的 i 去掉,转为一维dp。dp[j]表示容量为j的背包可装的最大价值。动态转移方程:dp[j] = max(dp[j], dp[j - weight[i]] + value[i])。

    一维dp需要注意几个问题:

    1.遍历顺序:遵从先背包后容量。并且容量要逆序遍历。

    解释:不可先容量后背包,先容量后背包这样背包中就只有一个物品。逆序遍历保证每个物品放入一次。

    代码

     1 class Solution {
     2 public:
     3     bool canPartition(vector<int>& nums) {
     4         int sum = 0;
     5         for(auto num:nums){
     6             sum += num;
     7         }
     8         if(sum % 2) return false;  //和为奇数必然不能分成两个和相同的子集
     9         sum /= 2;
    10         vector<int>dp(sum+1,0);
    11           
    12         for(int i = 1;i <nums.size();i++){
    13             for(int j = sum;j >= nums[i];j--){  //逆序
    14                 dp[j] = max(dp[j],dp[j-nums[i]] + nums[i]);
    15             }
    16         }
    17         if(sum == dp[sum]) return true;
    18         else return false;
    19     }
    20 };
  • 相关阅读:
    数组[切片]、字典、函数
    go结构体内存对齐
    微信支付流程
    自动化测试框架selenium、puyyer、pywight、splash
    变量、类型、指针
    Go学习目录
    I/O操作、go module
    杂文协程
    内存逃逸、枚举、字符串
    defer、异常处理、import
  • 原文地址:https://www.cnblogs.com/fresh-coder/p/14400451.html
Copyright © 2020-2023  润新知