代码随想录day42和day43 动态规划 模块01背包问题
“即使到不了远方,心中也要有远方的模样。”

文章目录

  • 1. 01背包理论基础
    • 1.1什么是背包问题
    • 1.2二维dp数组01背包
    • 1.3一维dp数组(滚动数组)01背包
  • 2.leetcode 416.分割等和子集
    • 2.1 详细思路及思考难点
    • 2.2具体步骤及代码实现
  • 3.leetcode 1049.最后一块石头的重量
    • 3.1详细思路及思考难点
    • 3.2具体步骤及代码实现
  • 4.leetcode 494.目标和
    • 4.1详细思路及思考难点
    • 4.2具体步骤及代码实现
  • 5.leetcode 474.一和零
    • 5.1详细思路及思考难点
    • 5.2具体步骤及代码实现

1. 01背包理论基础

1.1什么是背包问题


  背包问题大致可以分为以上几类,背包问题也就是选取物品放入重量为n的背包中,然后求背包的最大价值。

1.2二维dp数组01背包

  01背包问题—有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。

例子:假设背包最大重量为4,然后有三个物品,看如何将物品放入背包中能获取最大价值。

还是可以用动态规划的做题步骤来分析

   1.确定dp数组以及下标的含义

dp[i][j]对应的就是取索引[0,i]的物品,放入重量为j的背包中,得到价值dp[i][j]

   2. 确定递推公式

可以先将每种情况列举出来,然后再推导公式

由此可以推导出递推公式为dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i])
    每次遍历到dp[i][j]的时候都有两种取值情况dp[i-1][j]表示不放物品时的情况  
   dp[i-1][j-weight[i]]+value[i],weight[i]表示i的重量,value[i]表示i的价值。这就是表示添加新物品的情况
在上面两种情况中取最值

  3. dp数组的初始化问题

当背包重量为0时,可以初始化dp[i][0]=0;

  4.确定遍历顺序

这题的从前往后面遍历,可以先遍历背包再遍历物品也可以先便利物品再遍历背包,一般是先遍历物品

  5. 举例推导dp公式

代码示例

    public static void main(String[] args) {int[] weight = {1, 3, 4};int[] value = {15, 20, 30};int bagsize = 4;testweightbagproblem(weight, value, bagsize);}public static void testweightbagproblem(int[] weight, int[] value, int bagsize){int wlen = weight.length, value0 = 0;//定义dp数组:dp[i][j]表示背包容量为j时,前i个物品能获得的最大价值int[][] dp = new int[wlen + 1][bagsize + 1];//初始化:背包容量为0时,能获得的价值都为0for (int i = 0; i <= wlen; i++){dp[i][0] = value0;}//遍历顺序:先遍历物品,再遍历背包容量for (int i = 1; i <= wlen; i++){for (int j = 1; j <= bagsize; j++){if (j < weight[i - 1]){dp[i][j] = dp[i - 1][j];}else{dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + value[i - 1]);}}}//打印dp数组for (int i = 0; i <= wlen; i++){for (int j = 0; j <= bagsize; j++){System.out.print(dp[i][j] + " ");}System.out.print("\n");}}

1.3一维dp数组(滚动数组)01背包

  上面用二维数组来解决01背包问题,其实也可以用一维数组(也叫做滚动数组)来解决01背包问题。其核心也就是将二维数组压缩成一维数组。
假设背包最大重量为4,然后有三个物品,看如何将物品放入背包中能获取最大价值。

  那还是按照动态规划的做题步骤来分析

   1.确定dp数组以及下标的含义

dp[j]对应的就是背包重量为j的时候对应的最大价值dp[j]

   2. 确定递推公式

可以先将每种情况列举出来,然后再推导公式

dp[j]是由dp[j-weight[i]]决定的,递推公式可以如下
dp[j]=Math.max(dp[j],dp[j-weight[i]]+value[i])

  3. dp数组的初始化问题

当背包重量为0时,可以初始化dp[0]=0;

  4.确定遍历顺序

这题先遍历物品的时候可以从前面往后面遍历,然后再背包的时候得从后面往前面进行倒序遍历。如果是顺序遍历的话物品就会重复添加,因为每个物品只能用一次,以免影响其他结果

  5. 举例推导dp公式

代码示例

    public static void main(String[] args) {int[] weight = {1, 3, 4};int[] value = {15, 20, 30};int bagWight = 4;testWeightBagProblem(weight, value, bagWight);}public static void testWeightBagProblem(int[] weight, int[] value, int bagWeight){int wLen = weight.length;//定义dp数组:dp[j]表示背包容量为j时,能获得的最大价值int[] dp = new int[bagWeight + 1];//遍历顺序:先遍历物品,再遍历背包容量for (int i = 0; i < wLen; i++){for (int j = bagWeight; j >= weight[i]; j--){dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);}}//打印dp数组for (int j = 0; j <= bagWeight; j++){System.out.print(dp[j] + " ");}}

2.leetcode 416.分割等和子集

力扣题目链接

2.1 详细思路及思考难点

  这题可以将其划分为01背包问题,给定一个数组,判断是否能将数组分成两个子集和相同的两个数组。要将数组分成两个相等的子集的话,数组中的和sum也就是必须是偶数(这是第一个判断条件),然后令target=sum/2;这就是子集的和,把target想象成一个背包的最大重量,现在就是让背包里面的物品的重量刚好能达到背包的最大重量,如果能达到就返回true,反之,return false。

2.2具体步骤及代码实现

  按照动态规划的做题步骤来分析

   1.确定dp数组以及下标的含义

dp[j]对应的就是背包重量为j的时候对应的最大价值dp[j]

   2. 确定递推公式

dp[j]是由dp[j-weight[i]]决定的,递推公式可以如下
dp[j]=Math.max(dp[j],dp[j-nums[i]]+nums[i]),这里nums[i]既可以表示重量也可以表示价值

  3. dp数组的初始化问题

当背包重量为0时,可以初始化dp[0]=0;

  4.确定遍历顺序

这题先遍历物品的时候可以从前面往后面遍历,然后再背包的时候得从后面往前面进行倒序遍历。因为每个物品只能用一次,以免影响其他结果

  5. 举例推导dp公式

代码实现

class Solution {public boolean canPartition(int[] nums) {if(nums==null || nums.length==0)return false;int sum=0;for(int a:nums){sum+=a;}if(sum%2!=0)return false;int targrt=sum/2;int[] dp=new int[targrt+1];//dp[0]=0;for(int i=0;i<nums.length;i++){for(int j=targrt;j>=nums[i];j--){dp[j]=Math.max(dp[j],dp[j-nums[i]]+nums[i]);}}return dp[targrt]==targrt;}
}

3.leetcode 1049.最后一块石头的重量

力扣题目链接

3.1详细思路及思考难点

  这题思路跟416.分割子集问题基本一致,可以将所有石头分成两份和相同的子集和,target=sum/2,然后将石头存入dp[target]中所能满足的最大价值,最终返回的结果是(sum-dp[target])-dp[target],(sum-dp[target])表示没有装入背包的所有的集合,然后减去装入背包的,就是碰撞之后剩下的量。

3.2具体步骤及代码实现

  按照动态规划的做题步骤来分析

   1.确定dp数组以及下标的含义

dp[j]对应的就是背包重量为j的时候对应的最大石头量dp[j]

   2. 确定递推公式

dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);

  3. dp数组的初始化问题

当背包重量为0时,可以初始化dp[0]=0;

  4.确定遍历顺序

这题先遍历物品的时候可以从前面往后面遍历,然后再背包的时候得从后面往前面进行倒序遍历。因为每个物品只能用一次,以免影响其他结果

  5. 举例推导dp公式

代码实现

class Solution {public int lastStoneWeightII(int[] stones) {int sum=0;for(int a:stones){sum+=a;}int target=sum>>1;int[] dp=new int[target+1];dp[0]=0;for(int i=0;i<stones.length;i++){for(int j=target;j>=stones[i];j--){dp[j]=Math.max(dp[j],dp[j-stones[i]]+stones[i]);}}return sum-dp[target]-dp[target];}
}

4.leetcode 494.目标和

力扣题目链接

4.1详细思路及思考难点

  将nums中的数值添加正负号之后,设正数和为x,那么负数的和就是sum-x(sum是nums数组中所有元素的和)。x-(sum-x)=target ==>x=(sum+target)/2。然后将x转换成填满大小为x的背包,需要dp[j]种方法。

4.2具体步骤及代码实现

  按照动态规划的做题步骤来分析

   1.确定dp数组以及下标的含义

dp[j]对应的就是背包重量为j的时候对应的最大价值dp[j]

   2. 确定递推公式

根据下面得出递推公式为dp[j]+=dp[j-nums[i]]

  • 已经有一个1(nums[i]) 的话,有 dp[4]种方法 凑成 dp[5]。
  • 已经有一个2(nums[i]) 的话,有 dp[3]种方法 凑成 dp[5]。
  • 已经有一个3(nums[i]) 的话,有 dp[2]中方法 凑成 dp[5]
  • 已经有一个4(nums[i]) 的话,有 dp[1]中方法 凑成 dp[5]
  • 已经有一个5 (nums[i])的话,有 dp[0]中方法 凑成 dp[5]

  3. dp数组的初始化问题

当背包重量为0时,可以初始化dp[0]=0;

  4.确定遍历顺序

这题先遍历物品的时候可以从前面往后面遍历,然后再背包的时候得从后面往前面进行倒序遍历。因为每个物品只能用一次,以免影响其他结果

代码实现

class Solution {public int findTargetSumWays(int[] nums, int target) {int sum=0;for(int a:nums){sum+=a;}int zs=(sum+target)/2;if((target+sum)%2!=0) return 0;if(zs<0)zs=-zs;int[] dp=new int[zs+1];if(target>sum)return 0;dp[0]=1;for(int i=0;i<nums.length;i++){for(int j=zs;j>=nums[i];j--){dp[j]+=dp[j-nums[i]];}}return dp[zs];}
}

5.leetcode 474.一和零

力扣题目链接

5.1详细思路及思考难点

  这题用二维dp数组来做,把每个字符串当作单独的物品,总共的0和1的个数当作背包的容量。

5.2具体步骤及代码实现

  按照动态规划的做题步骤来分析

   1.确定dp数组以及下标的含义

dp[i][j]表示当有i个0和j个1时的最大子集的大小

   2. 确定递推公式

根据下面得出递推公式为dp[i][j]=Math.max(dp[i][j],dp[i-zero][j-one]+1)

  3. dp数组的初始化问题

初始为0就可以

  4.确定遍历顺序

遍历字符串的时候顺序遍历,遍历0和1的时候倒叙

  5.推导dp数组

代码实现

class Solution {public int findMaxForm(String[] strs, int m, int n) {int[][] dp=new int[m+1][n+1];int zero,one;for(String s : strs){zero=0;one=0;for(char c:s.toCharArray()){if(c=='0'){zero++;}else if(c== '1'){one++;}}for(int i=m;i>=zero;i--){for(int j=n;j>=one;j--){dp[i][j]=Math.max(dp[i][j],dp[i-zero][j-one]+1);}}}return dp[m][n];}
}

动态规划--01背包问题详解相关推荐

  1. 动态规划---01背包问题详解

    与利润有关的背包问题. 问题描述: 一个商人带着一个能装m千克的背包去乡下收购货物,准备将这些货物卖到城里获利. 现有n种货源,且知第i种货物有wi千克,可获利pi元.请编写算法帮助商人收购货物,以获 ...

  2. 动态规划-01背包问题详解

    read,write,comprehend

  3. c语言背包问题装字母,C语言动态规划之背包问题详解

    01背包问题 给定n种物品,和一个容量为C的背包,物品i的重量是w[i],其价值为v[i].问如何选择装入背包的物品,使得装入背包中的总价值最大?(面对每个武平,只能有选择拿取或者不拿两种选择,不能选 ...

  4. 01背包问题详解(浅显易懂)

    01背包问题详解 01背包是一种动态规划问题.动态规划的核心就是状态转移方程,本文主要解释01背包状态转移方程的原理. 问题描述 01背包问题可描述为如下问题: 有一个容量为V的背包,还有n个物体.现 ...

  5. 动态规划解决0-1背包问题详解(图文并茂)

    动态规划解决0-1背包问题 这个是网上比较好的案例,因为原文有些地方晦涩难懂,对于刚接触动态规划问题的朋友来说很不友好,所以很对地方加入了我自己的见解,也是作为我的一次学习历程. 一.问题描述: 有n ...

  6. 动态规划专题 01背包问题详解【转】

    对于动态规划,每个刚接触的人都需要一段时间来理解,特别是第一次接触的时候总是想不通为什么这种方法可行,这篇文章就是为了帮助大家理解动态规划,并通过讲解基本的01背包问题来引导读者如何去思考动态规划.本 ...

  7. 0-1背包问题详解-动态规划-两种方法

    问题描述: 给定n种物品和一背包.物品i的重量为wi,其价值为vi, 背包容量为c.问应如何选择装入背包中的物品,使得背入背包的物品的总价值最大? 解析: 此问题形式化的描述是,给定c > 0, ...

  8. 0-1背包问题详解(一步一步超详细)

    1.什么叫01背包问题? 背包问题通俗的说,就是假如你面前有5块宝石分别为a, b, c, d, e,每块宝石的重量不同,并且每块宝石所带来的价值也不同(注意:这里宝石的重量的价值没有特定关系),目前 ...

  9. 九种 0-1 背包问题详解

    目录 动态规划概念 问题1:0-1背包问题 问题2:完全背包问题 问题3:多重背包问题 问题4:混合背包问题 问题5:二维背包问题 问题6:分组背包问题 问题7:有依赖的背包问题 (困难) 问题8:背 ...

最新文章

  1. OverflowError: cannot fit ‘int‘ into an index-sized integer
  2. 【深入剖析Tomcat笔记】第一篇 基础知识储备
  3. redis配置主从复制
  4. activity的启动窗口
  5. OneAPM CI与阿里云容器服务集成
  6. Cloud for Customer根据后台数据实时刷新的逻辑调试
  7. PAFF 和MBAFF
  8. 【转】关于Python脚本开头两行的:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用 – 指定文件编码类型...
  9. 聚类、K-Means、例子、细节
  10. BATJ一线大公司需要什么样的前端
  11. js版俄罗斯方块(二)
  12. mysql select count() count(1)_select count()和select count(1)的区别和执行方式讲解
  13. 第二次作业——个人项目实战之随机数独生成
  14. 基于信息论的特征选择算法综述
  15. 高中数学记录日志(2019人教A版必修二)
  16. Bootstrap 3 如何设置图片居中对齐
  17. 坐标方位角计算通用公式
  18. 【兴趣】儿时背诵过的朝代歌和节气歌
  19. 一篇搞懂场景测试(Test Scenario Analysis)
  20. 宽带中国战网平台CS中一般问题解答

热门文章

  1. WHQL徽标认证申请流程
  2. 502 问题怎么排查?
  3. 今天win10弹出了flash助手,禁用它
  4. javaweb网上宠物商城管理系统分前后台(源码+数据库+开题报告+ppt+文档)
  5. 7-19 评委打分 (15 分)
  6. Linux系统修复网络,Linux系统无法上网解决方案教程
  7. 从数据库读取数据,该数据作为参数传入万得的wsd命令中
  8. c/c++ 趣味程序百例
  9. 抖音短视频APP开发通过三种方式绘制图片
  10. 【动手学树莓派】成为时代的弄潮儿,不做局外人