【随想录12】01背包练习
动态规划01背包练习
01背包的题目:
416. 分割等和子集
1049. 最后一块石头的重量 II
494. 目标和
474. 一和零
416. 分割等和子集
类加所有数字为sum,如果sum为奇数返回false
然后试着将所有数字分成两份,如果其中有一份能达到sum/2 ,返回true,否则为false。
DFS, 暴力过不了所有的点
public static boolean canPart( int[] nums ) {int sum = 0;for ( Integer i : nums ) {sum += i;}return dfs( nums, 0, 0, sum );}private static boolean dfs( int[] nums, int index, int sum, int target ) {//base caseif ( nums.length == index ) {if ( sum == target ) {return true;} else {return false;}}//对于任意一个数,可与选或者不选return dfs( nums, index + 1, sum + nums[index], target )||dfs( nums, index + 1, sum, target );}
// 作者:winlsr
// 链接:https://leetcode-cn.com/problems/partition-equal-subset-sum/solution/dfs-dfs-bei-wang-lu-01bei-bao-dong-tai-g-4j1t/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
暴力+记忆化搜索
// 备忘录:也可用一个二维数组,一维表示元素和sum,一维表示当前索引indexprivate Map<String, Boolean> map = new HashMap<>();private boolean dfsAndMap( int[] nums, int index, int sum, int target ) {if ( nums.length == index ) {if ( sum == target ) {return true;} else {return false;}}//描述一个子问题的两个变量是 sum 和 index,组成 key 字符串String key = sum + "&" + index;if ( map.containsKey( key ) ) {return map.get( key );}boolean ret = dfs( nums, index + 1, sum + nums[index], target ) ||dfs( nums, index + 1, sum, target );map.put( key, ret );return ret;}
动态规划
等价关系是这样的:
从 [0…i] 这个区间里抽出若干个元素能够填满 sum / 2 的背包,
就一定可以把区间为全部、和为 sum 的整数拆分成两个相等的子集【1】【2】
dp[ i ][ j ]
的意思是,选 i
个数字,刚好等于 j
因此dp [ i ] [ j ]
有两种状态,true或者false。
public boolean canPartition(int[] nums) {int sum = 0;for (int num : nums) {sum += num;}if (sum % 2 == 1) {return false;}int target = sum / 2;int n = nums.length;boolean[][] dp = new boolean[n + 1][target + 1];dp[0][0] = true;for(int i=1;i<=n;i++){for(int j=1;j<=target;j++){// 不选,则当前状态和上一层状态相同if(j < nums[i-1]){dp[i][j]=dp[i-1][j];}else{// 选了当前元素, 上一层布尔值 || 选了当前元素的布尔值 dp[i][j]=dp[i-1][j] || dp[i-1][j-nums[i-1]];}}}return dp[n][target];}
一维优化
public boolean canPartition(int[] nums) {int sum = 0;for (int num : nums) {sum += num;}if (sum % 2 == 1) {return false;}int target = sum / 2;int n = nums.length;boolean[] dp = new boolean[target + 1];dp[0] = true;for(int i=1;i<=n;i++){for(int j=target;j>=nums[i-1];j--){dp[j]= dp[j-nums[i-1]] || dp[j];}}return dp[target];}
1049. 最后一块石头的重量 II
动态规划
class Solution {public int lastStoneWeightII(int[] stones) {int sum = 0;for (int s : stones) {sum += s;}int target = sum / 2;//初始化,dp[i][j]为可以放0-i物品,背包容量为j的情况下背包中的最大价值int[][] dp = new int[stones.length][target + 1];//dp[i][0]默认初始化为0//dp[0][j]取决于stones[0]for (int j = stones[0]; j <= target; j++) {dp[0][j] = stones[0];}for (int i = 1; i < stones.length; i++) {for (int j = 1; j <= target; j++) {//注意是等于if (j >= stones[i]) {//不放:dp[i - 1][j] 放:dp[i - 1][j - stones[i]] + stones[i]dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - stones[i]] + stones[i]);} else {dp[i][j] = dp[i - 1][j];}}}// System.out.println(dp[stones.length - 1][target]);return (sum - dp[stones.length - 1][target]) - dp[stones.length - 1][target];}
}
494. 目标和
DFS 搜索
int res = 0;public int findTargetSumWaysByDFS( int[] nums, int target ) {int sum = 0;for ( Integer i : nums ) {sum += i;}if ( sum < target ) {return 0;}dfs( nums, target, 0, 0 );return res;}public void dfs( int[] nums, int target, int sum, int index ) {if ( index == nums.length ) {if ( sum == target ) {res++;return;}}if ( index != nums.length ) {dfs( nums, target, sum - nums[index], index + 1 );dfs( nums, target, sum + nums[index], index + 1 );}}
DFS 方法二
class Solution {public int findTargetSumWays(int[] nums, int t) {return dfs(nums, t, 0, 0);}int dfs(int[] nums, int t, int u, int cur) {if (u == nums.length) {return cur == t ? 1 : 0;}int left = dfs(nums, t, u + 1, cur + nums[u]);int right = dfs(nums, t, u + 1, cur - nums[u]);return left + right;}
}
作者:AC_OIer
链接:https://leetcode-cn.com/problems/target-sum/solution/gong-shui-san-xie-yi-ti-si-jie-dfs-ji-yi-et5b/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
二维动态规划
目标和:给数组里的每个数字添加正负号得到target
数组和sum
,目标和targer
,
数字可以分为两堆,左边组合 x
, 右边组合 y
,
则
x + y = sum
, x - y = targer
,
那么
x + x = sum + targer
x = ( target + sum ) / 2
【3】
target是固定的,sum是固定的,y 就可以求出来
此时问题就是在集合nums中找出和为x
的组合。
也就是说问题有解需要满足两个条件
- 数字全部加起来大于 target
- (sum + target) % 2 != 0 要不然无法找到相应的左右组合使得题意成立。
定义dp[ i ] [ j ]
表示, 选 0-i 个数,恰好使得他们的和为 j 的方法数有 dp[ i ] [ j ]
种。
初试化 dp[ 0 ] [ 0 ] = 1
表示一个数都不选,他们的和恰好为0 的方法数有 1 种
对于第i
个数字,我们有两种选择:
选择将第
i
个数字放入左边的组合,
此时,数字还剩i - 1
个,背包的容量需要减去nums [ i ]
(此处相当于要凑j
,还差j-nums[i]
, 而这个信息在dp [ i - 1 ] [ j - nums [ i ] ]
存放着)递推式为
dp [ i ] [ j ] = dp [ i - 1 ] [ j - nums [ i ] ]
;选择放弃第i个数字,直接来到第i - 1个数字,
那么能满足和为 j 的方式就是上一行的值(dp[ i - 1] [ j ]
)递推式为
dp [ i ] [ j ] = dp [ i - 1 ] [ j ]
;当背包的容量小于第
i
个数字时,即j
<nums[ i ]
,无法将第i
个数字放入背包,只能跳过,递推式同2 【4】
此处相当于,剩下要凑的 数字 j
已经比 其他数字小了,无法
所以 dp [ i ] [ j ] = dp [ i - 1 ] [ j ]
public int findTargetSumWays( int[] nums, int target ) {int res = 0;int sum = 0;for ( int i : nums ) {sum += i;}if ( Math.abs( target ) > sum || (sum + target) % 2 != 0 ) {return 0;}int mid = (sum + target) / 2;int N = nums.length;int[][] dp = new int[N + 1][mid + 1];dp[0][0] = 1;for ( int i = 1; i <= N; i++ ) {for ( int j = 0; j <= mid; j++ ) {if ( j >= nums[i - 1] ) {// 两种选择的结果之和dp[i][j] = dp[i - 1][j] + dp[i - 1][j - nums[i - 1]];} else {// 背包的空间不足,只能选择不装物品 idp[i][j] = dp[i - 1][j];}}}return dp[N][mid];}
一维优化
public int findTargetSumWays(int[] nums, int target) {int res = 0;int sum = 0;for (int i : nums) {sum += i;}if (Math.abs(target) > sum || (sum + target ) % 2 != 0 ) {return 0;}int mid = (sum + target) / 2;int N = nums.length;int []dp = new int [mid+1];dp[0]=1;for (int i = 1; i <= N; i++) {for (int j = mid; j>=nums[i-1]; j--) {dp[j] = dp[j] + dp[j-nums[i-1]];}}return dp[mid];}
474. 一和零
暴力超时
int res = 0 ; public int findMaxForm(String[] strs, int m, int n) {List<String> path = new ArrayList<>();get(strs,0,m,n,0,0,path);return res;}public void get(String[] strs,int index, int m, int n,int numM,int numN,List<String> path ){if(numM <=m && numN<= n){res = Math.max(res,path.size());}else{return;}for(int i=index;i<strs.length;i++){path.add(strs[index]);int[] cur = count(strs[i]);get(strs,i+1,m,n,cur[0]+numM,cur[1]+numN,path);path.remove(path.size()-1);}}public int[] count(String s){int [] res = new int[2];int i = 0;int len = s.length();while(i<len){if(s.charAt(i) == '0'){res[0]++;}else{res[1]++;}i++;}return res;}
动态规划
参考【5】
public class Solution {public int findMaxForm(String[] strs, int m, int n) {int len = strs.length;int[][][] dp = new int[len + 1][m + 1][n + 1];for (int i = 1; i <= len; i++) {// 注意:有一位偏移int[] count = countZeroAndOne(strs[i - 1]);for (int j = 0; j <= m; j++) {for (int k = 0; k <= n; k++) {// 先把上一行抄下来dp[i][j][k] = dp[i - 1][j][k];int zeros = count[0];int ones = count[1];if (j >= zeros && k >= ones) {dp[i][j][k] = Math.max(dp[i - 1][j][k], dp[i - 1][j - zeros][k - ones] + 1);}}}}return dp[len][m][n];}private int[] countZeroAndOne(String str) {int[] cnt = new int[2];for (char c : str.toCharArray()) {cnt[c - '0']++;}return cnt;}
}
空间优化
public class Solution {public int findMaxForm(String[] strs, int m, int n) {int[][] dp = new int[m + 1][n + 1];dp[0][0] = 0;for (String s : strs) {int[] zeroAndOne = calcZeroAndOne(s);int zeros = zeroAndOne[0];int ones = zeroAndOne[1];for (int i = m; i >= zeros; i--) {for (int j = n; j >= ones; j--) {dp[i][j] = Math.max(dp[i][j], dp[i - zeros][j - ones] + 1);}}}return dp[m][n];}private int[] calcZeroAndOne(String str) {int[] res = new int[2];for (char c : str.toCharArray()) {res[c - '0']++;}return res;}
}
【1】https://leetcode-cn.com/problems/partition-equal-subset-sum/solution/0-1-bei-bao-wen-ti-xiang-jie-zhen-dui-ben-ti-de-yo/782571
【2】https://leetcode-cn.com/problems/partition-equal-subset-sum/solution/0-1-bei-bao-wen-ti-xiang-jie-zhen-dui-ben-ti-de-yo/
【3】https://leetcode-cn.com/problems/partition-equal-subset-sum/solution/yi-pian-wen-zhang-chi-tou-bei-bao-wen-ti-a7dd/
【4】https://leetcode-cn.com/problems/target-sum/solution/hen-xiang-xi-de-zhuan-hua-wei-0-1bei-bao-irvy/
【5】https://leetcode-cn.com/problems/ones-and-zeroes/solution/dong-tai-gui-hua-zhuan-huan-wei-0-1-bei-bao-wen-ti/
【随想录12】01背包练习相关推荐
- 代码随想录42——动态规划:0-1背包理论基础、0-1背包滚动数组、416分割等和子集
文章目录 1.0-1背包理论基础 1.1.概述 1.2.0-1背包 1.3.二维dp数组01背包--动规五部曲 1.4.完整测试代码 2.0-1背包滚动数组 2.1.一维滚动数组 2.2.一维dp数组 ...
- Dream City(01背包+小贪心)acm寒假集训日记21/12/30
题目如下: AC代码如下: #include<iostream> #include<algorithm> #include<cstring> #include< ...
- NYOJ 860 又见01背包
有n个重量和价值分别为wi 和 vi 的 物品,从这些物品中选择总重量不超过 W 的物品,求所有挑选方案中物品价值总和的最大值. 1 <= n <=100 1 <= wi < ...
- hdu 3449 Consumer 01背包
http://acm.hdu.edu.cn/showproblem.php?pid=3449 这个题AC的有点稀里糊涂(是1A过的),采用的01背包的方法: 思路:定义了两个数组用来存储最终结果和但购 ...
- hdu 3732(01背包转多重背包)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3732 思路:这么大的数据,用01背包肯定会TLE的,01背包转多重背包..最多也就11*11=121件 ...
- 洛谷 P1049 装箱问题(01背包)
一道水题,但看到好久没有发博客了,再一看是一道noip普及组t4,就做了. 题目链接 https://www.luogu.org/problemnew/show/P1049 解题思路 一道裸的01背包 ...
- 杭电1171(01背包求解)
题目: Problem Description Nowadays, we all know that Computer College is the biggest department in HDU ...
- HDu 3449 (有依赖的01背包) Consumer
题意: 有n件物品,对应有不同的价格和价值,这是典型的01背包.但现在有了一个限制,要买物品先买能装这件物品的特定的盒子,盒子的价值为0 代码理解得还不是太好,感觉这是一个"二重" ...
- [UVa1213]Sum of Different Primes(递推,01背包)
题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...
最新文章
- 测试 ClownFish、CYQ、Entity Framework、Moon、MySoft、NHibernate、PDF、XCode数据访问组件性能...
- mysql8.0最低需要多少内存_MySQL8.0内存相关参数介绍
- python读取文件类型_python准确判断文件类型
- SSH(Struts2+Hibernate+Spring)开发策略
- zabbix邮件发不出去
- WebBrowser一点心得,如果在Javascript和Winform代码之间实现双向通信
- Discuz! Database Error(2003) notconnect 问题解決
- Java 高效编程之 Builder 模式
- 虚拟机克隆后修改网络部分
- Excel实验情况对比排序
- java 生成pdf 下载_java生成PDF,并下载到本地
- 华硕h410csm怎么开启_华硕主板怎么开启uefi模式?华硕主板BIOS开启uefi模式详细方法...
- Ubuntu 16.04安装sogou拼音输入法
- 大白菜u盘制作工具教程
- 常用网络测试软件,常用的网络故障检测工具有哪些
- SAP_FI统驭科目
- 淘宝网 286亿海量图片存储与处理架构
- 微信版QQ群助手 | 微信也可以折叠群聊了
- 上海市建平中学2021年高考成绩查询,2021年上海市高中排名一览表
- 黄页88网站之加密字符串破解