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];
}
先上一张图:测试数据为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的更多相关文章
-
[Swift]LeetCode416. 分割等和子集 | Partition Equal Subset Sum
Given a non-empty array containing only positive integers, find if the array can be partitioned into ...
随机推荐
-
Android -- 时间轴(ListView)
1. 实现效果
-
photoshop,黑白转彩色单色
方法一: 打开 色相/饱和度 面板,勾选上 着色, 然后调节 明度 滑块. 方法二: 前面方法的缺点是会将修改直接塌陷到图层,如果想不塌陷,可以使用色相蒙板: 同样勾选 着色
-
coursera机器学习笔记-多元线性回归,normal equation
#对coursera上Andrew Ng老师开的机器学习课程的笔记和心得: #注:此笔记是我自己认为本节课里比较重要.难理解或容易忘记的内容并做了些补充,并非是课堂详细笔记和要点: #标记为<补 ...
-
PHOG特征
PHOG特征 2016年7月13日 21:07:57 什么是PHOG PHOG是Pyramid HOG(pyramid histogram of oriented gradient)的简称,是在图像尺 ...
-
25数据查询的各种小玩法-select上(必学)-天轰穿sqlserver视频教程
大纲:简单查询-选择数据列,使用字符串,改变列标题,使用数据运算 优酷超清地址,为了冲优酷的访问量,所以这里只放优酷的地址了,其实其他网站还是都传了的哈.
-
编写优秀jQuery插件的10个技巧
前言:在开发过很多 jQuery 插件以后,我慢慢的摸索出了一套开发jQuery插件比较标准的结构和模式.这样我就可以 copy & paste 大部分的代码结构,只要专注最主要的逻辑代码就行 ...
-
SQL server 存储过程的建立和调用
存储过程的建立和调用 --1.1准备测试需要的数据库:test,数据表:物料表,采购表if not exists (select * from master.dbo.sysdatabases whe ...
-
vue 日期时间过滤器
来自:https://blog.csdn.net/m0_37068028/article/details/72898154 侵删 来自:https://segmentfault.com/a/11900 ...
-
PNP的学习-EPNP
EPNP主要是利用已知的3d点,通过PCA选择4个控制点,建立新的局部坐标系,从而将3d坐标用新的控制点表示出来. 然后,利用相机投影模型和2d点,转换到相机坐标系中,再在相机坐标系中建立和世界坐标系 ...
-
工作流管库的bpmn部署在数据库中
工作流管库的bpmn部署在数据库中 DB_schema_update_false 没有表则创建 有表则报错 DB_SCHEMA_UPDATE_TRUE 没有表则创建 有表则不创建 脚本更新则更新数据 ...