[leetcode]416. Partition Equal Subset Sum

Given a non-empty array 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.
给定一个非空数组,是否能把数组划分为两个和相等的子集。
Note:
Each of the array element will not exceed 100.
The array size will not exceed 200.

Example 1:

Input: [1, 5, 11, 5]

Output: true

Explanation: The array can be partitioned as [1, 5, 5] and [11].
Example 2:

Input: [1, 2, 3, 5]

Output: false

Explanation: The array cannot be partitioned into equal sum subsets.

解析:
很明显,既然是等和,问题就可以变形成为数组中求指定和的问题。即目标值为 SUM/2 的动归问题。
因为每一个数都保证为正数。理论上,对于这种题,需要生成全部和的组合,然后遍历和的结果是否等于 SUM/2。
我先声明一个大小为 SUM/2 的数组名叫DP,然后对给定数组进行遍历,
拿第一个例子来说:

给定数组为
Input:     [1, 5, 11, 5]

因为总和为22,所以创建一个22/2=11的DP数组,另外加一个下标为0的方便计算。DP[i]表示i值可以用数组中元素相加而来。
  
 0, 1, 2, 3, 4, 5, 6, 7 ,8 ,9,10,11
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

下面模拟运行过程:
对于第一个值1,他能生成的和只有1,就是他自己。在代码中,j从目标值11下降到1,找到在DP数组中j和1相减存在的值,目前只有j为1时DP[1-1]==1,所以DP[1] = 1,表示使用[1]可以生成1这个和。

 0, 1, 2, 3, 4, 5, 6, 7 ,8 ,9,10,11
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

对于第二个值5,j从目标值11下降到5,找到在DP数组中j和5相减存在的值,目前有j为6时DP[6-5]==1,DP[5-5]==1,所以DP[6]=DP[5] = 1。

 0, 1, 2, 3, 4, 5, 6, 7 ,8 ,9,10,11
[1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0]

对于第三个值11,j从目标值11下降到11,找到在DP数组中j和11相减存在的值,只有一个值就是11,DP[11-11]==1,所以DP[11] = 1。

 0, 1, 2, 3, 4, 5, 6, 7 ,8 ,9,10,11
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

在循环中,当发现DP[11]为1时,就表示已经能够用当前的这些值组成一半的和,可以提前退出。


public boolean canPartition(int[] nums) {
        
    	int sum  = 0;
    	for(int i = 0; i<nums.length; i++){
    		sum+=nums[i];
    	}
    	if(sum %2==1)return false;
    	
    	int halfSum = sum/2;
    	
    	int [] dp = new int [halfSum+1];
    	dp[0] = 1;
    	
    	for(int i = 0; i < nums.length; i++){
    		
    		for(int j = halfSum; j >= nums[i]; j --){
    			
    			if(dp[j - nums[i]] == 1)dp[j] = 1;
    			if(dp[halfSum] == 1)return true;;
    		}
    	}
    	return false;
    }

总结:
观察DP数组,可以看到在对输入的数组循环过程中,每一次实际上都是将当前的输入数组元素与之前能够生成的所有和相加,有点类似BFS算法自己感觉。这个数组求和划分的题十分经典,而DP[0]的设置也比较巧妙的简化了代码。将目标和指定为数组来填充,然后每一步填写能生成的和,这种技巧可以帮助解其他的DP题。

原文地址:https://www.cnblogs.com/yumingle/p/6653374.html