概述
class Solution { public boolean canPartition(int[] nums) { int sum=0; for (int num:nums) sum+= num; if(sum % 2 == 1) return false; else{ sum /=2; int n=nums.length; // dp[i][j] 表示 如果我们取前i个数字,且背包容量为j的情况下,最多能放入多少东西 int dp[][]=new int[n][sum + 1]; // dp[0][0] 为初始状态,表示,没有任何没有东西没有体积,其余部分初始化 for(int i=nums[0];i<=sum;i++){ dp[0][i] = nums[0]; } //遍历n个数字,即视为n个产品 for(int i=1;i<n;i++){ //加入了这种物品后更新状态 for(int j=nums[i];j<=sum;j++){ dp[i][j]=Math.max(dp[i-1][j], dp[i-1][j-nums[i]]+nums[i]); } } //放满了才能表示正好1/2 if(dp[n-1][sum]==sum) return true; else return false; } } }
补充另一种写法:
1 public boolean canPartition(int[] nums) { 2 int sum = 0; 3 4 for (int num : nums) { 5 sum += num; 6 } 7 8 if ((sum & 1) == 1) { 9 return false; 10 } 11 sum /= 2; 12 13 int n = nums.length; 14 boolean[][] dp = new boolean[n+1][sum+1]; 15 for (int i = 0; i < dp.length; i++) { 16 Arrays.fill(dp[i], false); 17 } 18 19 dp[0][0] = true; 20 21 for (int i = 1; i < n+1; i++) { 22 dp[i][0] = true; 23 } 24 for (int j = 1; j < sum+1; j++) { 25 dp[0][j] = false; 26 } 27 28 for (int i = 1; i < n+1; i++) { 29 for (int j = 1; j < sum+1; j++) { 30 dp[i][j] = dp[i-1][j]; 31 if (j >= nums[i-1]) { 32 dp[i][j] = (dp[i][j] || dp[i-1][j-nums[i-1]]); 33 } 34 } 35 } 36 37 return dp[n][sum]; 38 }
参考:https://leetcode.com/problems/partition-equal-subset-sum/discuss/90592/01-knapsack-detailed-explanation
先上一张图:测试数据为nums=[1,3,3,5],判断是否可以分割为两个和为6的数组(不要求连续)。
下面解释一下思路,初始化二维数组dp,初始化全部为false,这个数组中的每一个元素表示:
在前i个元素中,任选其中0~i个元素(可以一个不选,也可以全都选),这些元素的和,是否恰好等于j。
具体来说,dp[0][0]表示前0个元素是否可以组成和为0的情况,这作为前提条件,设置为true。
除这个元素之外的第一列:
dp[1][0],表示前1个元素是否可以组成和为0的情况。答案是:可以组成。只要不选择任何元素,其和值就是0。
dp[2][0],表示前2个元素是否可以组成和为0的情况。答案是:可以组成,只要不选择任何元素,其和值就是0.
dp[3][0],dp[4][0]也是同样道理,均为true。
除dp[0][0]之外的第一行:
dp[0][1],表示前0个元素是否可以组成和为1的情况。答案是:不可以。前0个就是没有任何元素,其和不可能大于0.
dp[0][2]……dp[0][6]也是同样道理,均为false。
下面从dp[1][1]开始判断,一行一行的判断。如图绿色的行。
如果这个元素“上面”是true,那么当前元素就是true。表示当前元素不被选择,可以直接组成和i-1个元素是一样的值。
如果当前元素的列标j>=nums[i-1],则进一步判断。如图,就是比较每一个单元格的“上标注”是否大于等于“右标注”。
如果满足条件,则进一步判断:当前行的上一行的[上标-右标]的元素是否是true。
按照这个转移条件,一行一行的判断,最右下角的元素就是所求结果。表示前i个元素,是否可以组成sum值。
通过分析,可以发现,只要“最后一列”,出现过一次true,那么最终的结果就一定是ture,也就可以提前停止循环了。
具体来说,上图蓝色行的最后一列,即dp[3][6]是true,那么其下面的元素肯定都是true。也就无需后面的判断了。这样理论上可以提高效率。
转载于:https://www.cnblogs.com/asenyang/p/9784914.html
最后
以上就是霸气老虎为你收集整理的leetcode416的全部内容,希望文章能够帮你解决leetcode416所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复