Day40——Dp专题

news2024/11/24 4:52:10

文章目录

    • 三、01背包
      • 8.分割等和子集
      • 9.最后一块石头的重量 II
      • 10.目标和
      • 11. 一和零


三、01背包

8.分割等和子集

题目链接:416. 分割等和子集 - 力扣(LeetCode)

思路:我们构造两个子集使得两个子集的和相等,其实就是让我们构造其中一个子集的和是否等于sum / 2,若存在说明能分割等和子集。如果sum为奇数,是不能分割等和子集的。

换句话说,题目就是让我们从nums[]中选择一些物品,使得物品的总和恰好为target(sum / 2),为此可以转化为01背包问题

递归五部曲

  • 确定dp数组以及下标含义

dp[j]表示 背包总容量(所能装的总重量)是j,放进物品后,背的最大重量为dp[j]

  • 确定递推公式

01背包的递推公式为:dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

本题,相当于背包里放入数值,那么物品i的重量是nums[i],其价值也是nums[i]。

所以递推公式:dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);

  • dp数组初始化

从dp[j]的定义来看,首先dp[0]一定是0,这样才能让dp数组在递归公式的过程中取的最大的价值,而不是被初始值覆盖了

  • 确定遍历顺序

如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!

  • 打印举例dp数组

image-20221206104953909

Code

一维

class Solution {
    public boolean canPartition(int[] nums) {
        if(nums == null || nums.length == 0) return false;
        int n = nums.length;
        int sum = 0;
        for(int num : nums){
            sum += num;
        }

        if(sum % 2 != 0) return false;
        int target = sum/2;
        int[] dp = new int[target+1];
        for(int i = 0; i < n; i++){
            for(int j = target; j >= nums[i]; j--){
                dp[j] = Math.max(dp[j],dp[j-nums[i]] + nums[i]);
            }
        }
        return dp[target] == target;
    }
}

二维

class Solution {
    public boolean canPartition(int[] nums) {
        int sum = 0;
        for (int i = 0; i < nums.length; i++) {
            sum += nums[i];
        }

        if (sum % 2 == 1)
            return false;
        int target = sum / 2;

        //dp[i][j]代表可装物品为0-i,背包容量为j的情况下,背包内容量的最大价值
        int[][] dp = new int[nums.length][target + 1];

        //初始化,dp[0][j]的最大价值nums[0](if j > weight[i])
        //dp[i][0]均为0,不用初始化
        for (int j = nums[0]; j <= target; j++) {
            dp[0][j] = nums[0];
        }

        //遍历物品,遍历背包
        //递推公式:
        for (int i = 1; i < nums.length; i++) {
            for (int j = 0; j <= target; j++) {
                //背包容量可以容纳nums[i]
                if (j >= nums[i]) {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - nums[i]] + nums[i]);
                } else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }

        return dp[nums.length - 1][target] == target;
    }
}

9.最后一块石头的重量 II

题目链接:1049. 最后一块石头的重量 II - 力扣(LeetCode)

思路:两个两个集合总和越平均越好,即尽量接近于各占一半

状态计算:f[j] = max(f[j], f[j - stones[i]] + stones[i])

最后一块石头的的最小重量:sum - 2 * f[half]

动规五部曲:

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

dp[j]表示容量(这里说容量更形象,其实就是重量)为j的背包,最多可以背最大重量为dp[j]

相对于 01背包,本题中,石头的重量是 stones[i],石头的价值也是 stones[i] ,可以 “最多可以装的价值为 dp[j]” == “最多可以背的重量为dp[j]”

  • 确定递推公式

本题中 f[j] = max(f[j], f[j - stones[i]] + stones[i])

  • dp数组初始化

dp[j]都初始化为0就可以了,这样在递归公式dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);中dp[j]才不会初始值所覆盖,dp数组的大小为target = sum/2 + 1

  • 确定遍历顺序

如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!

  • 打印并举例dp数组

image-20221206113829022

最后dp[target]里是容量为target的背包所能背的最大重量。

那么分成两堆石头,一堆石头的总重量是dp[target],另一堆就是sum - dp[target]。

在计算target的时候,target = sum / 2 因为是向下取整,所以sum - dp[target] 一定是大于等于dp[target]的

那么相撞之后剩下的最小石头重量就是 (sum - dp[target]) - dp[target]。

Code

一维

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

二维

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];
    }
}

10.目标和

题目链接:力扣题目链接

思路:每个数前面加+ 或者 -可以联想01背包,要么0要么1我们将数组分为两部分,一部分为正数的p,一部分为负数的ne

我们想要sum(p) + sum(ne) == S,而数组的和是已知的即sum(p) + sum(ne) == sum

两式相加化简得sum(p) = (sum + S) / 2 = targrt,也就是说我们要从nums[]里边选几个数使其和为target

于是就转换为求容量恰好为taeget的01背包问题。

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

dp[j] 表示:填满j(包括j)这么大容积的包,有dp[j]种方法

  • 确定递推公式

例如:dp[j],j 为5,

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

那么凑整dp[5]有多少方法呢,也就是把 所有的 dp[j - nums[i]] 累加起来。

dp[j] += dp[j-nums[i]];
  • dp数组初始化

f[0] = 1,体积为0(和为0),那就是一个物品都不放,有一种方案。

  • 确定遍历顺序

nums放在外循环,target在内循环,且内循环倒序。

 for(int i = 0; i < nums.length ;i++){
            for(int j = size; j >= nums[i]; j--){
                dp[j] += dp[j-nums[i]];
            }
        }
  • 举例推导dp数组

输入:nums: [1, 1, 1, 1, 1], S: 3

bagSize = (S + sum) / 2 = (3 + 5) / 2 = 4

dp数组状态变化如下:

image-20221206131138813

Code

一维

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

11. 一和零

题目链接:474. 一和零 - 力扣(LeetCode)

image-20221206183219143

动规五部曲

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

dp[i][j]:最多有i个0和j个1的strs的最大子集的大小为dp[i][j]

  • 确定递推公式

trs里的字符串有zeroNum个0,oneNum个1。

dp[i][j] 就可以是 dp[i - zeroNum][j - oneNum] + 1

然后我们在遍历的过程中,取dp[i][j]的最大值。

所以递推公式:dp[i][j] = max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);

  • dp数组初始化

1背包的dp数组初始化为0就可以。

因为物品价值不会是负数,初始为0,保证递推的时候dp[i][j]不会被初始值覆盖

  • 确定遍历顺序

for循环遍历物品,内层for循环遍历背包容量且从后向前遍历

  • 举例推导dp数组

image-20221206183616541

Code

二维

class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        int[][] dp = new int[m+1][n+1];
        int oneNum,zeroNum;
        for(String str : strs){
            oneNum = 0;
            zeroNum = 0;
            for(char ch : str.toCharArray()){
                if(ch=='0'){
                   zeroNum++; 
                }else{
                    oneNum++;
                }
            }
            //倒叙遍历
            for(int i = m; i >= zeroNum; i--){
                for(int j = n; j>=oneNum; j--){
                    dp[i][j] = Math.max(dp[i][j], dp[i - zeroNum][j - oneNum]+1);
                }
            }
        }
        return dp[m][n];
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/66568.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaScript:初始JS 以及 基础语法

前端三件套&#xff1a; HTML: 生成网页控件 例如&#xff1a;生成 文本框 多选框 下拉列表 等 (人的身体) CSS: 修饰网页上的控件 例如&#xff1a;修饰文本框为圆形 &#xff08;人的衣服&#xff09; JavaSript: 在这些控件上添加逻辑 例如&#xff1a;获取文本框的值 然…

哈工大体系结构lab3 —— 流水线处理器的verilog实现

流水线处理器的verilog实现 是的我刚刚验收完最后一个实验&#xff0c;所以怀着激动的心情&#xff0c;把当时其中一个留档的代码发出来&#xff0c;还算较为清晰&#xff0c;仅供没有思路的同学参考。造完cache&#xff0c;我的生活终于可以恢复正轨了&#xff0c;这几天折磨的…

web安全之SQL盲注的靶场练习和分析

目录 SQL盲注-报错回显盲注 SQL盲注-时间盲注 SQL盲注-布尔盲注 SQL盲注-报错回显盲注 在burp里面进行动态抓包&#xff0c;判断符号闭环&#xff0c;如图明显为闭环 列数3时报错&#xff0c;判断当前列数为2 强行报错注入 &#xff0c;如图获取到版本号 uname1212 unio…

h5视频落地页知识点整理

一、视频在苹果中自动播放&#xff08;借助微信SDK&#xff09; 1.引入微信SDK <script src"http://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script> 2. document.addEventListener(WeixinJSBridgeReady, function() { const timer setInte…

如何签署exe或Windows应用程序?

本文您将了解为什么要签署Windows应用程序以及如何签署EXE或Windows应用程序的步骤指南。 代码签名是一种确保软件来自经过验证的正版软件发行商的方法。使用代码签名证书唱WindowsEXE文件可确保可执行文件或Windows应用程序不会被恶意行为者更改或修改。 Windows应用程序签名…

2022年NPDP新版教材知识集锦--【第五章节】(2)

《产品经理认证(NPDP)知识体系指南(第2版)》已于2022年4月正式上架发行&#xff0c;新版教材自2022年11月NPDP考试起使用。将新版NPDP教材中的相关知识点进行了整理汇总&#xff0c;包括详细设计与规格阶段相关内容&#xff0c;快来看看吧。 【市场研究工具】(全部内容获取文末…

华为机试 - 无向图染色

目录 题目描述 输入描述 输出描述 用例 题目解析 算法源码 题目描述 给一个无向图染色&#xff0c;可以填红黑两种颜色&#xff0c;必须保证相邻两个节点不能同时为红色&#xff0c;输出有多少种不同的染色方案&#xff1f; 输入描述 第一行输入M(图中节点数) N(边数) …

使用reshape2 R包进行在线长数据和宽数据相互转化

数据是数据分析的基础。我们常见的数据一般存储在excel表格&#xff0c;或者txt文档中。今天我们来看看长数据和宽数据&#xff0c;以及如何进行两者之间的相互转换。 1&#xff0e;宽数据和长数据 宽数据 如图1所示&#xff0c;宽数据是我们最常见的数据存储形式&#xff0c…

[附源码]Python计算机毕业设计Django校园订餐管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

nginx配置文件组成

1.配置文件的组成 ​ 配置文件由全局块events块http块组成 1.1 全局块 ​ 从配置文件开始到events之间的内容&#xff0c;主要会设置一些影响Nginx服务器整体运行的配置指令&#xff0c;主要包括配置运行Nginx服务器的用户(组)、允许生成的worker process数&#xff0c;进程pid…

Java数据结构与Java算法学习Day06---堆(简略笔记记录)

目录 一、堆 96 1.1堆的定义 96 1.2堆的API设计 97 1.3堆---堆的插入方法 98 1.4堆---堆的删除最大元素方法 99 1.5堆---堆的测试 100 二、堆排序 101 2.1堆排序 101 一、堆 96 1.1堆的定义 96 堆实际上也是利用数据结构实现的&#xff0c;用树实现的特殊结构&…

(mac M1)Flutter环境搭建

下载Flutter SDK&#xff0c;需要科学上网。 将Flutter永久添加到PATH中 1 sudo vim ~/.bash_profile 打开文件 2 export PATHpwd/flutter/bin:$PATH 将这个添加到前几行环境变量设置中 3 :wq 退出vim 4 source ~/.bash_profile 配置马上生效命令 运行 flutter doctor 命令&a…

【Linux】yum的介绍和使用

本期主题&#xff1a;yum介绍和使用博客主页&#xff1a;小峰同学分享小编的在Linux中学习到的知识和遇到的问题小编的能力有限&#xff0c;出现错误希望大家不吝赐作为程序员&#xff0c;不会有人还没女朋友吧。 目录 &#x1f341;1.软件包是什么&#xff1f; &#x1f341;…

[附源码]Python计算机毕业设计Django小型银行管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Qwt开发笔记(二):Qwt基础框架介绍、折线图介绍、折线图Demo以及代码详解

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/128194710 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软…

单片机硬件和软件延时、RTOS相对延时和绝对延时

已剪辑自: https://mp.weixin.qq.com/s/-RPLQn4KO9Aqu1fpfZeOKA 前不久有个读者在问关于延时的问题&#xff0c;大概就是问&#xff1a;软件延时和硬件延时是啥意思&#xff1f;做项目时他俩有什么区别&#xff1f; 今天就来讲讲关于硬件延时和软件延时的内容&#xff0c;以及…

[GitHub]将本地文件上传远程仓库(安装,创建SSHKey,上传远程仓库)

目录 什么是GitHub 注册账户以及创建仓库 安装Git 配置Git ​编辑 将本地项目上传远程仓库 创建本地仓库 创建远程仓库 克隆远程仓库到本地 什么是GitHub github是一个基于git的代码托管平台&#xff0c;付费用户可以建私人仓库&#xff0c;我们一般的免费用户只能使用公共…

Android 动画实现 从基础到自定义

1. 基础使用 由于是继承了ValueAnimator类 所以使用的方法十分类似&#xff1a;XML 设置 / Java设置1.1 Java设置 ObjectAnimator animator ObjectAnimator.ofFloat(Object object, String property, float ....values); // Object object&#xff1a;需要操作的对象 // Str…