leetcode416
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 ...
- 通过netty把百度地图API获取的地理位置从Android端发送到Java服务器端
本篇记录我在实现时的思考过程,写给之后可能遇到困难的我自己也给到需要帮助的人. 写的比较浅显,见谅. 在写项目代码的时候,需要把Android端的位置信息传输到服务器端,通过Netty达到连续传输的效 ...
随机推荐
- vue,在模块中动态添加dom节点,并监听
在这里,onclick事件没有作用,因为它指向的是window,如果写为this.click页面显示为undefined, 我采用的是通过class绑定事件,但是会有一个问题,那就是当你渲染多个事件时 ...
- guava-retrying 源码解析(阻塞策略详解)
这是一种策略,用于决定重试者应如何在重试尝试之间进行阻止.通常这只是一个thread.sleep(),但是如果需要的话,实现可能更复杂. 一.阻塞策略相关的类或接口 1.阻塞策略接口:BlockStr ...
- windows10 vs2017 C++连接MySQL
安装mysql8.0 x64 创建test数据库,user表,插入数据如下: +----+------+----------+-----------------+ | id | name | pass ...
- acrgis 解决矢量转栅格分辨率过大造成连续值变离散且出现空白
目标:解决北京河流矢量polygon 转栅格的问题 设置栅格大小和影像一致30*30----结果发现,因为cell过大,原本连续的是矢量面变得不连续了,特别细的河流会出现间断(如下图所示): 1号 网 ...
- api管理平台
安装和介绍 安装要求:(centos安装环境) nodejs(7.6+) mongodb(2.6|+) 安装get和编译的工具 yum -y install wget make gcc gcc-c++ ...
- lombok安装
今天学习spring boot 时候发现的lombok挺好用的,我这个使用的是spring boot 管理的版本,如果其他的可能需要你们自己去添加版本了,开发工具使用的是idea. maven: &l ...
- 《深入.NET平台和C#编程》内部测试题-笔试试卷答案
1) 以下关于序列化和反序列化的描述错误的是( C). a) 序列化是将对象的状态存储到特定存储介质中的过程 b) 二进制格式化器的Serialize()和Deseria ...
- Vue.js学习使用心得(四)——组件
一.组件 组件(Component)是 Vue.js 最强大的功能之一. 组件可以扩展 HTML 元素,封装可重用的代码. 组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界 ...
- AFN 二次封装
#import "YQDataManager.h" #import <YYModel/YYModel.h> #pragma mark - 数据model基类 @impl ...
- Linux下安装oracle的步骤和一些问题
今天在Linux64位系统安装oracle数据库,折腾了一天,终于搞定了,现在把安装步骤梳理下,防止以后忘记: (以下内容来自http://blog.163.com/junwu_lb/blog/ ...