• 416. 分割等和子集


    416 分割等和子集

    给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

    注意:

    每个数组中的元素不会超过 100
    数组的大小不会超过 200
    示例 1:

    输入: [1, 5, 11, 5]

    输出: true

    解释: 数组可以分割成 [1, 5, 5] 和 [11].

    示例 2:

    输入: [1, 2, 3, 5]

    输出: false

    解释: 数组不能分割成两个元素和相等的子集.

    思路


    判断是否有等和子集,对数组求和,那么问题转化为,在数组是否有一个序列的和等于数组和的一半
    问题变成了一个01背包问题;
    利用动态规划来求解,普通解法是建立一个二维数组

    (dp[i][j]) 表示从(0)(i)之间是否存在一种方案使得和为(j) 初始是 0即false;

    • 解决边界问题

    (dp[i][0] = true) : 因为当和为(0)的时候,数组下标(0)(i)之间存在一种方案使得 和为(0) (什么元素都不选)
    (dp[0][nums[0]] = true) : 因为当和为(nums[0])的时候,选择(nums[0])为方案

    • 解决递推问题

    (if(j>=nums[i])) 那么(nums[i]) 可以不被选取,也可以被选取。只需要将两者情况取或(只要有一个为true 则dp[i][j]为true):
    (dp[i][j] = dp[i-1][j] | dp[i][j-nums[i]];)

    (if(j<nums[i])) 那么该元素不被选取:
    (dp[i][j] = dp[i-1][j];)

    class Solution {
    public:
        bool canPartition(vector<int>& nums) {
            int n = nums.size();
            if(n < 2) return false;
            int sum = accumulate(nums.begin(),nums.end(),0);
            int MaxNum = *max_element(nums.begin(),nums.end());
            //判断sum是否为奇数,按位与 最后一位是0 则为偶数,为1 则为奇数
            if(sum & 1) return false;
            int target = sum/2;  //转化为 0 1 背包问题,即判断数组中是否存在和为target 的序列
    
            if(MaxNum > target) return false;
    
            //定义动态规划数组 dp[i][j] 表示从0到i之间 有没有和为j的序列
            vector<vector<int> > dp(n,vector<int> (target+1,0));
    
            for(int i=0;i<n;i++)
            {
                dp[i][0] = true;
            }
    
            dp[0][nums[0]] = true;
    
            for(int i =1;i<n;i++)
            {
                int num = nums[i];
                for(int j=1;j<=target ;j++)
                {
                    if(j>=num)
                    {
                        dp[i][j] = dp[i-1][j] | dp[i-1][j-num];
                    }
                    else
                    {
                        dp[i][j] = dp[i-1][j];
                    }
                }
    
                 if(dp[i][target]) return true;
            }
    
            return dp[n-1][target];
        }
    };
    

    优化空间


    把dp二维数组优化为一维的,这是因为每一次状态转移,dp[i][j]的值只与上一行数组有关。

    class Solution {
    public:
        bool canPartition(vector<int>& nums) {
            int n = nums.size();
            if(n < 2) return false;
            int sum = accumulate(nums.begin(),nums.end(),0);
            int MaxNum = *max_element(nums.begin(),nums.end());
            //判断sum是否为奇数,按位与 最后一位是0 则为偶数,为1 则为奇数
            if(sum & 1) return false;
            int target = sum/2;  //转化为 0 1 背包问题,即判断数组中是否存在和为target 的序列
    
            if(MaxNum > target) return false;
    
            vector<int> dp(target+1,0);
            dp[0] = true;
            if(nums[0] <= target)
                dp[nums[0]] = true;
    
            for(int i=1;i<n;i++)
            {
                for(int j = target;nums[i] <= j; j--)
                {
                    if(dp[target])
                    {
                        return true;
                    }
                    dp[j] = dp[j] | dp[j - nums[i]];
                }
            }
            return dp[target];
        }
    };
    

    链接

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/partition-equal-subset-sum

  • 相关阅读:
    创建的第二个随笔
    Jq基础简介
    从VG中去除PV unknown device
    redhat using publicyum
    Oracle 11g 安装文件说明
    WP8教程: 第一个WP8应用(一)
    WP8教程: 第一个WP8应用(二)
    sqlplus 的登录方式
    redhat7 安装oracle11g 缺少pdksh包
    jquery实现一个substr截取字符串的小效果
  • 原文地址:https://www.cnblogs.com/jiashun/p/LeetCode_416.html
Copyright © 2020-2023  润新知