算法: 零一背包问题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

零一背包问题解析

这个问题本质上是让我们找出一个集合中是否有几个数字能够和一个特定的值(在这个问题中,该值是 sum/2)。

实际上,这是一个 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个元素已经到达jdp[ 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]]

Java 解法

public boolean canPartition(int[] nums) 
    int sum = 0;
    
    for (int num : nums) 
        sum += num;
    
    
    if ((sum & 1) == 1) 
        return false;
    
    sum /= 2;

    int n = nums.length;
    boolean[][] dp = new boolean[n+1][sum+1];
    for (int i = 0; i < dp.length; i++) 
        Arrays.fill(dp[i], false);
    
    
    dp[0][0] = true;
    
    for (int i = 1; i < n+1; i++) 
        dp[i][0] = true;
    
    for (int j = 1; j < sum+1; j++) 
        dp[0][j] = false;
    
    
    for (int i = 1; i < n+1; i++) 
        for (int j = 1; j < sum+1; j++) 
            dp[i][j] = dp[i-1][j];
            if (j >= nums[i-1]) 
                dp[i][j] = (dp[i][j] || dp[i-1][j-nums[i-1]]);
            
        
    
   
    return dp[n][sum];

优化空间后解法

public boolean canPartition(int[] nums) 
    int sum = 0;
    
    for (int num : nums) 
        sum += num;
    
    
    if ((sum & 1) == 1) 
        return false;
    
    sum /= 2;
    
    int n = nums.length;
    boolean[] dp = new boolean[sum+1];
    Arrays.fill(dp, false);
    dp[0] = true;
    
    for (int num : nums) 
        for (int i = sum; i > 0; i--) 
            if (i >= num) 
                dp[i] = dp[i] || dp[i-num];
            
        
    
    
    return dp[sum];

Python 解法

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        total_sum = sum(nums)
        if total_sum & 1 == 1 : return False
        half_sum = total_sum // 2
        dp = [True] + [False] * half_sum
        for num in nums:
            for j in range(half_sum, num-1, -1):
                dp[j] |= dp[j-num]
            if dp[-1]:
                return True
        return dp[-1]
        

以上是关于算法: 零一背包问题416. Partition Equal Subset Sum的主要内容,如果未能解决你的问题,请参考以下文章

刷题416. Partition Equal Subset Sum

[动态规划] leetcode 416 Partition Equal Subset Sum

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

动态规划入门——传说中的零一背包问题

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

416 分割等和子集