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. DoTween的用法

    using UnityEngine;using System.Collections;using DG.Tweening;using UnityEngine.UI; public class Test ...

  2. 带通滤波 matlab

    巴特沃斯:1.带阻滤波器设计带阻滤波器指标:阻带上边界频率:5Kz:阻带下边界频率:7Kz:通带上边界频率:2Kz:通带下边界频率:9Kz:通带最大衰减:1dB:阻带最小衰减:20dB:设计程序如下: ...

  3. NOIP2011提高组 选择客栈

    原题 题目描述 丽江河边有n 家很有特色的客栈,客栈按照其位置顺序从 1 到n 编号.每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k-1 表示),且每家客栈都设有一家咖啡店,每家咖 ...

  4. nodejs -- event 模块, 事件模块.

    1. 注册事件 on 或者 addListener,触发事件 emit 1-1简单的使用: var EventEmitter = require('events').EventEmitter; var ...

  5. ela的UNASSIGNED索引修复

    1.查找UNASSIGNED未分片的索引: #curl -s "http://localhost:9200/_cat/shards" -u username:passwd | gr ...

  6. c# 如何 使用共用体

    用起来真的方便 转摘如下: C#借助FieldOffset属性实现共用体与强制类型转换 这两天被C#的强制类型转换弄得有点不习惯.事出如此. 在C#中,我打算读二进制文.文件的结构很简单,一连串的紧密 ...

  7. Python全栈之路----数据类型—列表

    1.列表是一个数据的集合,集合内可以放任何数据类型,可对集合进行方便的增删改查操作.列表里面的数可以重复. L1 = [ ] #定义空列表 L2 = [ 'a' , 'b' , 'c' , 'd' ] ...

  8. mysql命令行使用

    连接数据库   mysql -P 端口号 -h 远程机地址/ip -u 用户名 -p mysql -uroot -p123456 修改数据库密码 mysqladmin -uroot -p123456 ...

  9. NN 激活函数 待修改

    Softmax 函数/算法 https://www.zhihu.com/question/23765351 RELU 激活函数及其他相关的函数 http://blog.csdn.net/u013146 ...

  10. 用我所学去讲C语言指针

    文章更新,更加详细的介绍请看这篇:https://www.cnblogs.com/lulipro/p/7460206.html 很多人不敢讲C的指针,有些人讲不清,有些人怕讲错.初生牛犊不怕虎,就让我 ...