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;
} }
}

补充另一种写法:

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

参考: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。也就无需后面的判断了。这样理论上可以提高效率。

leetcode416的更多相关文章

  1. [Swift]LeetCode416. 分割等和子集 | Partition Equal Subset Sum

    Given a non-empty array containing only positive integers, find if the array can be partitioned into ...

  2. 通过netty把百度地图API获取的地理位置从Android端发送到Java服务器端

    本篇记录我在实现时的思考过程,写给之后可能遇到困难的我自己也给到需要帮助的人. 写的比较浅显,见谅. 在写项目代码的时候,需要把Android端的位置信息传输到服务器端,通过Netty达到连续传输的效 ...

随机推荐

  1. Core Json 序列化相关问题

    //返回json  大小写 配置            services.AddMvc()                    .AddJsonOptions( op => op.Serial ...

  2. session_unset,session_destroy

    session_unset()释放当前用户在内存中已经创建的所有$_SESSION变量,但不删除session文件以及不释放对应的sessionid session_destroy()删除当前用户对应 ...

  3. locate语法

    1.命令格式:locate [参数] [文件] 2.命令功能:locate命令可以在搜寻数据库时快速找到档案,数据库由updatedb程序来更新,updatedb是由cron daemon周期性建立的 ...

  4. Python全栈之路----常用数据类型--集合

    集合(set):无序的,不重复的数据组合,它的主要作用如下:  · 去重,把一个列表变成集合,就自动去重了  · 关系测试,测试两组数据之间的交集.差集.并集等关系 1.基本操作:修改,删除,合并 & ...

  5. Js高级 部分内容 面向对象

    1.单列模式 2.工厂模式 3.构造函数 (1)类 js天生自带的类 Object基类 Function  Array  String  Number  Math Date Boolean Regex ...

  6. struct 和typedef struct

    1.typedef (1)typedef的使用 定义一种类型的别名,而不只是简单的宏替换(见陷阱一).用作同时声明指针型的多个对象 typedef char* PCHAR; // 一般用大写,为cha ...

  7. 自己封装一个弹窗JS

    在我们平时的开发中,一定有很多地方需要用到弹窗提示功能.而系统自带的弹窗奇丑无比,而且我们不能自主控制.因此我们在开发过程中,自己封装一个弹窗JS方便我们使用. 代码demo如下: // JavaSc ...

  8. python 【winerror2】系统找不到指定的路径

    # _*_ coding:utf-8_*_from selenium import webdriver driver = webdriver.Firefox()driver.get("htt ...

  9. 装系统时 System clock uses UTC 问题

    装系统也装了至少不下50次了,每次都是傻瓜一样的按照第一印象在弄,从未想过为啥,装到这里的时候,System clock uses UTC 勾不勾呢,每次都是百度,然后装完这一次下一次又忘了,这是没有 ...

  10. edit this cookie chrome插件 (HttpAnalyzerStdV3 获取Cookie 后,再用edit this cookie添加cookie)

    插件下载地址及安装方法:http://www.bkill.com/download/154494.html 博客提供下载地址:https://files.cnblogs.com/files/Fooo/ ...