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. jsonp 实现原理

      Jsonp原理: 首先在客户端注册一个callback, 然后把callback的名字传给服务器. 此时,服务器先生成 json 数据.然后以 javascript 语法的方式,生成一个funct ...

  2. 13--Python入门--文件读写--CSV&Excel文件

    EXCEL文件 import pandas as pd excel=pd.read_excel('read_excel.xlsx') print(excel) CSV文件 import pandas ...

  3. scrapy中selenium的应用

    引入 在通过scrapy框架进行某些网站数据爬取的时候,往往会碰到页面动态数据加载的情况发生,如果直接使用scrapy对其url发请求,是绝对获取不到那部分动态加载出来的数据值.但是通过观察我们会发现 ...

  4. Dubbo透传traceId/logid的一种思路

    前言: 随着dubbo的开源, 以及成为apache顶级项目. dubbo越来越受到国内java developer欢迎, 甚至成为服务化自治的首选方案. 随着微服务的流行, 如何跟踪整个调用链, 成 ...

  5. 安装Python 3.6 在Ubuntu 16.04 LTS 版本

    Collecting tensorflow Could not find a version that satisfies the requirement tensorflow (from versi ...

  6. php环境和使用方法

    下载好所需要的软件 (含phpmywind  phpstudy  navicat for my sql ) 如果Navicat 的试用期过期,请使用通杀navicat 的通杀Navica11_2-XX ...

  7. GCD XOR(UVa 12716)

    题意:输入整数n(1<=n<=30000000),有多少对整数(a,b)满足1<=b<=a<=n,且gcd(a,b)=a xor b. 题解:设c=gcd(a,b),因为 ...

  8. c——根据天数输出日期

    <c语言程序设计>(第三版)何钦铭 P190 #include<stdio.h> void month_day(int year,int yearday,int *pmonth ...

  9. 如果debug调试的时候中断总是停在析构函数的delete[] p上

    如果debug调试的时候中断总是停在析构函数的delete[] p上,那可能 有两种情况: 1.调用析构函数的这个对象没有被分配空间,先找到调用调用析构函数出错的这个对象, 然后查看它是否被分配了空间 ...

  10. MySQL查询不使用索引汇总 + 如何优化sql语句

    不使用索引原文 : http://itlab.idcquan.com/linux/MYSQL/918330.html MySQL查询不使用索引汇总 众所周知,增加索引是提高查询速度的有效途径,但是很多 ...