[LeetCode] 416. Partition Equal Subset Sum 解题报告

来源:互联网 发布:js点击按钮弹出提示框 编辑:程序博客网 时间:2024/05/01 20:13

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:

  1. Each of the array element will not exceed 100.
  2. The array size will not exceed 200.

Example 1:

Input: [1, 5, 11, 5]Output: trueExplanation: The array can be partitioned as [1, 5, 5] and [11].

Example 2:

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

这个问题看起来还是有一些难度的,实际上是一个01背包问题,通过动态规划来解决。把数字看成是物品,数字的值看成是价值,重量不限,目标也不太一样,需要确定是否能够达到价值加起来是否能达到总和的一半。这个思路想起来有点复杂,我们换一种思考方式:

源代码来自:https://discuss.leetcode.com/topic/62312/java-solution-similar-to-backpack-problem-easy-to-understand

我们先有一个boolean型数组dp[],用来存储对应的数值能不能通过加这些数字得到,数组的大小就是总和的一半(超过一半的不需要判断),记作volume,然后从小到大来判断是否能达到,最终返回dp[volume]的值即可,如果为true,则说明能够通过数字的加和得到综合的一半。

boolean[] dp = new boolean[volumn + 1];

接下来,我们就通过两种循环来依次判断基于前i个数,能凑成的总和是哪些,如果可以凑成,那么将dp对应的位置设置为true即可。具体的方法就和背包问题非常相似了。
dp[j] = dp[j] || dp[j - nums[i - 1]];
上面这句话可以解读为:对于前i个数字,能凑成总和为j的,有两种情况:1.如果dp数组中已经记录了可以凑成j,那肯定没问题;2.如果当前的大小j,减去当前这个数字,还能够凑成的话,那么加上当前数字,肯定也可以凑成,所以这时候也能凑成j。

这时,弱鸡的我想到了一个问题,如果遇到重复的数字怎么办?其实并没有关系,因为这针对的前i个数字,有重复的继续算就可以了。下面代码,我作了一点点修改,就是先对nums进行排序,排序的复杂度是nlogn,加上以后,对于数量级并没有影响。但是在循环里面,会大量出现dp[j]=true的情况,这样可以减少后面的比较次数。

public class Solution {public boolean canPartition(int[] nums) {if (nums == null || nums.length == 0) {return true;}int volumn = 0;Arrays.sort(nums);for (int num : nums) {volumn += num;}if (volumn % 2 != 0) {return false;}volumn /= 2;boolean[] dp = new boolean[volumn + 1];dp[0] = true;for (int i = 1; i <= nums.length; i++) {for (int j = volumn; j >= nums[i - 1]; j--) {dp[j] = dp[j] || dp[j - nums[i - 1]];}}return dp[volumn];}}


0 0
原创粉丝点击