算法: 等分子集总和416. Partition Equal Subset Sum

Posted AI架构师易筋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法: 等分子集总和416. Partition Equal Subset Sum相关的知识,希望对你有一定的参考价值。

416. Partition Equal Subset Sum

Given a non-empty array nums containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.

Example 1:

Input: nums = [1,5,11,5]
Output: true
Explanation: The array can be partitioned as [1, 5, 5] and [11].

Example 2:

Input: nums = [1,2,3,5]
Output: false
Explanation: The array cannot be partitioned into equal sum subsets.
 

Constraints:

  • 1 <= nums.length <= 200
  • 1 <= nums[i] <= 100

动态规划解法

直觉:所以让我们一步一步开始,专注于这个过程:

  1. 由于我们必须使两个子集的总和相等,因此我们的第一个条件是检查给定数组的总和是否可以分为两个相等的部分,如果总和为奇数,则根本不可能进行分区,如果总和为偶数那么就有机会了。
    例如:
1.) arr1-> [1,5,11,5]   and     2.) arr2 -> [1,5,3,11] 
	Both arr1 and arr2 has even sum but 1st can be partitioned into ([1,5,5] & [11]) and 2nd can not.
  1. 现在让我们试着把它想象成 0/1 背包问题:
  • 由于在 0/1 背包中,对于每个具有值 v 的物体,我们有 2 个选择,是否将其保留在具有一定重量 W 的背包中。
  • 与本例相同,我们在数组中有 n 个元素,我们有两种选择可以将其保留在子集 1 或子集 2 中(包含在一个中是直接排除在另一个中),并且背包/子集的重量将为 sum/2。
  1. 所以现在我们剩下的目标是我们只需要关心一个子集,因为如果一个子集的权重 sum/2 是可能的,那么另一个子集肯定会有权重 sum/2。

  2. 所以现在使用子集求和问题代码,我们只需要检查是否可能有一个具有 sum = totalSum/2 的子集;

  3. 其实这是一个0/1背包问题,对于每个数字,我们可以选择它或不选择它。让我们假设 dp[i][j] 表示是否可以从前 i 个数字中获得特定和 j。如果我们可以从 0-i 中挑选出这样的一系列数字,其总和为 j,则 dp[i][j] 为真,否则为假。

基本情况:dp[0][0] 为真;(零数由总和 0 组成,为真)

转移函数:对于每个数,如果我们不取它,dp[i][j] = dp[i-1][j],这意味着如果前i-1个元素已经变成了j,dp[ i][j] 也会变成 j(我们可以忽略 nums[i])。如果我们选择 nums[i]dp[i][j] = dp[i-1][j-nums[i]],表示j由当前值nums[i]组成,其余由之前的其他数字组成。因此,转移函数是 dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i]]

class Solution 
    public boolean canPartition(int[] nums) 
        int len = nums.length;
        int sum = 0;
        for (int n: nums) 
            sum += n;
        if (sum % 2 != 0)
            return false;
        sum /= 2;
        boolean[][] dp = new boolean[len + 1][sum + 1];
        for (int i = 0; i <= len; i++) 
            for (int s = 0; s <= sum; s++) 
                if (i == 0 || s == 0) dp[i][s] = false;
                else if (nums[i - 1] > s) dp[i][s] = dp[i - 1][s]; // if curr sum value is greater than the current element value then just skip(take previous value)
                else if (nums[i - 1] == s) dp[i][s] = true;  // we got required sum
                else dp[i][s] = dp[i - 1][s] || dp[i - 1][s - nums[i - 1]];
            
        
        
        return dp[len][sum];
    

参考

https://leetcode.com/problems/partition-equal-subset-sum/discuss/1624101/JAVA-or-Memoization-to-Optimized-DP-or-Detailed-Explanation

https://leetcode.com/problems/partition-equal-subset-sum/discuss/90592/01-knapsack-detailed-explanation

以上是关于算法: 等分子集总和416. Partition Equal Subset Sum的主要内容,如果未能解决你的问题,请参考以下文章

算法: 数组是否可以分成和相等的两个子集416. Partition Equal Subset Sum

(Java) LeetCode 416. Partition Equal Subset Sum —— 分割等和子集

LeetCode_Partition Equal Subset Sum

题目地址(416. 分割等和子集)

416分割等和子集

算法: 零一背包问题416. Partition Equal Subset Sum