• [LeetCode] 416 Partition Equal Subset Sum


    原题地址:

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

    题目:

    题解:

    这道题给定一个数组,求这个数组是否可以分成两个数组,使这两个数组各自的元素之和相等。

    首先,假如这个数组本身的元素之和是一个奇数时,是不能把这个数组分成两个和相等的数组的。因此,利用这一点我们可以排除掉很多情况,直接得出结果。

    而对于数组本身元素之和为偶数的情况,我们才需要算法去解决。我们可以将问题转化为以下的形式:是否有一个子数组的元素之和,恰好等于原数组元素之和的一半呢?而对于原数组中的每一个元素,都有两种状态:在子数组里面或者不在子数组里面(先假设存在这个子数组)。这样一看,我们就能发现这个问题与0-1背包问题非常相似,因此我们可以采用0-1背包问题的解法去解决这道问题。

    在这道题目中,原数组里面的每个元素都可以看作是一种物品,而这件物品的重量和价值都为元素值;原数组的和的一半可看作背包的最大承重量,而当背包能放下物品的最大价值为原数组和的一半时,就返回真,否则返回假。

    采用二维数组解决的代码如下:

    class Solution {
    public:
       bool canPartition(vector<int>& nums) {
            int sum = accumulate(nums.begin(), nums.end(), 0);
            if (sum % 2 == 1) return false;
            sum /= 2;
            int ** a = new int*[nums.size()];
            for (int i = 0; i < nums.size(); i++) {
                a[i] = new int[sum + 1];
            }
            for(int i=nums[0];i<=sum;i++){
                 a[0][i] = nums[0];
            }
            for (int i = 1; i < nums.size(); i++) {
                for (int j = nums[i]; j <= sum; j++) {
                    a[i][j] = a[i - 1][j] > a[i - 1][j - nums[i]] + nums[i] ? a[i - 1][j] : a[i - 1][j - nums[i]] + nums[i];
                }
            }
           return a[nums.size() - 1][sum] == sum;
       }
    
    };

    上面的代码值得注意的是下面这一句:

    for(int i = nums[0]; i <= sum;i++){
        a[0][i] = nums[0];
    }

    由于这道题目中“物品”是从第0件开始算起的,这和平时做的0-1背包问题从第1件物品算起的初始化方法不一样,值得注意。

    采取一维数组解决的代码:

    class Solution {
    public:
       bool canPartition(vector<int>& nums) {
            int sum = accumulate(nums.begin(), nums.end(), 0);
            if (sum % 2 == 1) return false;
            sum /= 2;
            int * dp = new int[sum + 1];for (int i = 0; i < sum + 1; i++) {
           dp[i] = 0;
         }for (int i = 0; i < nums.size(); i++) { for (int j = sum; j >= nums[i]; j--) { dp[j] = dp[j] > dp[j - nums[i]] + nums[i] ? dp[j] : dp[j - nums[i]] + nums[i]; } } return dp[sum] == sum; } };

    用一维数组来解决这个问题,就无需考虑上面从第几件物品算起的问题,只需改一下第一层循环i的起始值即可。

    这道题给了我一个启发:这类题目,即物品(数组元素)有存在与否两种状态的题目,都可以用0-1背包的思想和解法进行解决。推广一下,可以用背包问题的思想去解决。(假如允许数组元素重复岂不是可以用完全背包的方法解决?)

  • 相关阅读:
    转:C/C++基本数据类型所占字节数
    转:为什么C++中空类和空结构体大小为1?
    转:内存字节对齐
    转:100层楼扔两个鸡蛋的问题
    移动互联网
    辗转相除法
    斐波那契数列
    error C2783: 无法为“T”推导 模板 参数
    创新工场和海豚浏览器宣讲会启示
    转:快速排序的一个小问题没想明白,求助各位
  • 原文地址:https://www.cnblogs.com/fengziwei/p/7755865.html
Copyright © 2020-2023  润新知