力扣 416. 分割等和子集

news2024/9/22 13:37:31

题目来源:https://leetcode.cn/problems/partition-equal-subset-sum/description/

C++题解(思路来源代码随想录) :

背包问题有多种背包方式,常见的有:01背包、完全背包、多重背包、分组背包和混合背包等等。一个商品如果可以重复多次放入是完全背包,而只能放入一次是01背包,本题中是01背包。

把01背包问题套到本题上来。

  • 背包的体积为sum / 2
  • 背包要放入的商品(集合里的元素)重量为元素的数值,价值也为元素的数值
  • 背包如果正好装满,说明找到了总和为 sum / 2 的子集。
  • 背包中每一个元素是不可重复放入。

以上分析完,我们就可以套用01背包,来解决这个问题了。

  1. 确定dp数组以及下标的含义。二维数组: dp[i][j]表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
  2. 确定递推公式。两种情况:不放物品i:由dp[i - 1][j]推出,即背包容量为j,里面不放物品i的最大价值,此时dp[i][j]就是dp[i - 1][j]。(其实就是当物品i的重量大于背包j的重量时,物品i无法放进背包中,所以背包内的价值依然和前面相同。);放物品i:由dp[i - 1][j - weight[i]]推出,dp[i - 1][j - weight[i]] 为背包容量为j - weight[i]的时候不放物品i的最大价值,那么dp[i - 1][j - weight[i]] + value[i] (物品i的价值),就是背包放物品i得到的最大价值。所以递归公式: dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])
  3. dp数组初始化。一定要和dp数组的定义吻合,否则到递推公式的时候就会越来越乱。首先从dp[i][j]的定义出发,如果背包容量j为0的话,即dp[i][0],无论是选取哪些物品,背包价值总和一定为0。状态转移方程可以看出i 是由 i-1 推导出来,那么i为0的时候就一定要初始化,即i为0,存放编号0的物品的时候,各个容量的背包所能存放的最大价值。当 j < weight[0]的时候,dp[0][j] 应该是 0;当j >= weight[0]时,dp[0][j] 应该是value[0]。
  4. 确定遍历顺序。有两个遍历的维度:物品与背包重量。都可以! 但是先遍历物品更好理解
  5. 举例推导dp数组。
class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int len = nums.size();
        int sum = 0;
        for(int i = 0; i < len; i++) {
            sum += nums[i];
        }
        if(sum % 2 == 1) return false;
        vector<vector<int>> dp(len, vector<int>(sum/2+1, 0));
        for(int ii = nums[0]; ii <= sum/2; ii++) {
            dp[0][ii] = nums[0];
        }
        // 相当于包容量为sum/2,在len个物品中挑选,能装满则返回true。
        // 表示从0-j的元素中,取出和小于k的最大值。
        for(int j = 1; j < len; j++) {
            for(int k = 0; k <= sum/2; k++) {
                if(k < nums[j]) dp[j][k] = dp[j-1][k];
                else dp[j][k] = max(dp[j-1][k], dp[j-1][k-nums[j]]+nums[j]);
            }
        }
        if(dp[len-1][sum/2] == sum/2) return true;
        else return false;
    }
};

# 使用一维dp数组(滚动数组)

在使用二维数组的时候,递推公式:dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);

其实可以发现如果把dp[i - 1]那一层拷贝到dp[i]上,表达式完全可以是:dp[i][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i]);

与其把dp[i - 1]这一层拷贝到dp[i]上,不如只用一个一维数组了,只用dp[j](一维数组,也可以理解是一个滚动数组)。这就是滚动数组的由来,需要满足的条件是上一层可以重复利用,直接拷贝到当前层。

在一维dp数组中,dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]。

注意:遍历顺序必须先遍历物品再遍历包容量,且更新内层for循环需要递减(从后往前),因为滚动数组的更新需要用到未更新的前面元素,如果是递增(从前往后),前面更新的元素会影响后面的元素。

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = 0;

        // dp[i]中的i表示背包内总和
        // 题目中说:每个数组中的元素不会超过 100,数组的大小不会超过 200
        // 总和不会大于20000,背包最大只需要其中一半,所以10001大小就可以了
        vector<int> dp(10001, 0);
        for (int i = 0; i < nums.size(); i++) {
            sum += nums[i];
        }
        // 也可以使用库函数一步求和
        // int sum = accumulate(nums.begin(), nums.end(), 0);
        if (sum % 2 == 1) return false;
        int target = sum / 2;

        // 开始 01背包
        for(int i = 0; i < nums.size(); i++) {
            for(int j = target; j >= nums[i]; j--) { // 每一个元素一定是不可重复放入,所以从大到小遍历
                dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
            }
        }
        // 集合中的元素正好可以凑成总和target
        if (dp[target] == target) return true;
        return false;
    }
};

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

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

相关文章

实验笔记之——Android项目的适配

android有一个很烦人的点就是版本之间差距较大&#xff0c;且不兼容&#xff0c;导致不同版本之间代码兼容很容易出问题&#xff0c;一个常见的例子就是几年前自己开发的app&#xff0c;几年后再用竟然配置不了。。。为此&#xff0c;写下本博客记录一下配置旧项目的过程。 …

IDA+Frida分析CTF样本和Frid源码和objection模块

文章目录 一些资料IDA调试命令IDA调试安卓的10个技巧objection基本使用 Wallbreaker1frida源码阅读之frida-java 第一个实例EasyJNI第二个实例objection资料 art_trace2.pyart_trace2.js IDAFrida分析CTF样本和Frid源码和objection模块 一些资料 IDA调试命令 adb devices adb…

Redis 如何解决缓存雪崩、缓存击穿、缓存穿透难题

前言 Redis 作为一门热门的缓存技术&#xff0c;引入了缓存层&#xff0c;就会有缓存异常的三个问题&#xff0c;分别是缓存击穿、缓存穿透、缓存雪崩。我们用本篇文章来讲解下如何解决&#xff01; 缓存击穿 缓存击穿: 指的是缓存中的某个热点数据过期了&#xff0c;但是此…

我们一起聊聊Docker And Dockerfile

目录 一、前言 二、了解Dockerfile 三、Dockerfile 指令 四、多阶段构建 五、Dockerfile 高级用法 六、小结 一、前言 对于开发人员来说&#xff0c;会Docker而不知道Dockerfile等于不会Docker&#xff0c;上一篇文章带大家学习了Docker的基本使用方法&#xff1a;《一文…

Mybatis where 1=1 会导致索引失效?

背景 这几天在网上百度看到有说法 where 11 会导致索引失效 实践 1.直接where 条件 这是我自己本地建立的表&#xff0c;索引也看到了&#xff0c;是这个index_shopname 2.where 11 and 条件 这个是加了11的&#xff0c;可以看到也是走了索引的 3.直接select * from whe…

测试平台——用户模块开发

这里写目录标题 一、创建子应用二、用户注册设计1、用户注册模型类设计a、Django认证系统提供了用户模型类User&#xff0c;为什么还要定义User模型类?b、AbstractUserc、自定义用户模型类的字段有d、User模型类编写好了就可以了吗? 2、用户注册序列化器类设计a、注意b、单字…

基于分级安全的OpenHarmony架构设计

本文转载自 OpenHarmony TSC 官方微信公众号《峰会回顾第1期 | 基于分级安全的OpenHarmony架构设计》 演讲嘉宾 | 付天福 回顾整理 | 廖 涛 排版校对 | 李萍萍 嘉宾简介 付天福&#xff0c;OpenHarmony技术指导委员会安全及机密计算TSG负责人&#xff0c;华为公司科学家委员会…

机器人“瓦力”近在咫尺?谷歌最新的RT-2 AI模型简介

“首创”的机器人 AI 模型能够识别垃圾并执行复杂的动作。 上周五&#xff0c;谷歌 DeepMind 宣布了机器人变形器 2&#xff08;RT-2&#xff09;&#xff0c;这是一种“首次推出”的视觉-语言-行动&#xff08;VLA&#xff09;模型&#xff0c;利用从互联网上抓取的数据&…

理解 CSS 中的 Containing Block

前言 在开始本文之前先来看一个例子&#xff0c;下面一段简单的 html 代码&#xff0c;布局很简单&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"w…

clickhouse调研报告2

由Distributed表发送分片数据 clickhouse分区目录合并 clickhouse副本协同流程 clickhouse索引查询逻辑 clickhouse一级索引生成逻辑(两主键) clickhouse的data目录下包含如下目录: [root@brfs-stress-01 201403_10_10_0]# ll /data01/clickhouse/data total 4 drwxr-x---…

【Linux操作系统】网络配置详解:从原理到实践(详细通俗讲明DNS)

导语&#xff1a;网络配置是Linux系统中的一项重要任务&#xff0c;合理的网络配置可以保证计算机与其他设备的正常通信。本文将详细介绍Linux网络配置的原理和实践&#xff0c;包括网络配置原理、查看网络IP和网关、测试网络连通性、网络环境配置、设置主机名和hosts映射以及主…

获取全部的地区并生成表格

思路 写文章的时间2023-8-4&#xff0c;大部分网页设置的区域都是先是省&#xff0c;然后通过省获取对应的市&#xff0c;再通过市获取对应的区&#xff0c;以此类推。所以模拟的请求也是按照这个逻辑&#xff0c;先获取所有的省&#xff0c;再获取所有的市&#xff0c;最后获取…

【2023华数杯全国大学生数学建模竞赛】C题 母亲身心健康对婴儿成长的影响第一、二问

第一问部分截图 第二问部分截图 参考文献 理论和可直接运行代码获取参见&#xff1a;理论和可直接运行代码获取参见&#xff1a;理论和可直接运行代码获取参见&#xff1a;理论和可直接运行代码获取参见&#xff1a; 有人看的话更新后续问题思路。

【项目经验】产研流程(超级详细的步骤)

一、产研流程简述 项目立项-——定需求——Sprint需求宣讲会——技术方案——技术方案评审会——开发及单元测试——测试用例评审会——提测——测试——Sprint评审会——发版——Sprint复盘会 二、产研流程详情 以下部分根据Sprint里程碑节点进行循环&#xff08;sprint周期…

Java8实战-总结12

Java8实战-总结12 Lambda表达式Lambda 和方法引用实战第1步&#xff1a;传递代码第2步&#xff1a;使用匿名类第3步&#xff1a;使用Lambda表达式第4步&#xff1a;使用方法引用 复合Lambda表达式的有用方法比较器复合逆序比较器链 函数复合 Lambda表达式 Lambda 和方法引用实…

【C++】从无到有了解并掌握C++面向对象编程的三大特性——封装、继承、多态

前置知识&#xff1a;类和对象 参考书籍&#xff1a;《C Primer 第五版》 目录 什么是面向过程&#xff1f;什么是面向对象&#xff1f; 一、封装 1、封装的含义以及如何实现封装 1.1 访问限定符&#xff08;访问说明符&#xff09; 1.2 什么是封装&#xff1f; 2、封装的优点…

2023年华数杯选题人数发布!!

该选题人数&#xff0c;主要基于根据各个平台开赛后12小时各项数据统计&#xff0c;进行评估&#xff08;方法见注释&#xff09;&#xff0c;最终得出2023年华数杯选选题人数&#xff0c;大致为 题号选题人数A120B159C420 注释&#xff1a;选题人数来源&#xff1a;源自各个平…

Java字符串常量池以及new String(“abc“)到底创建了几个对象?各种字符串到底相不相等?

new String(“abc”)到底创建了几个对象&#xff1f; 字符串常量池 是 JVM 为了提升性能和减少内存消耗针对字符串&#xff08;String 类&#xff09;专门开辟的一块区域&#xff0c;主要目的是为了避免字符串的重复创建。 1.如果字符串常量池中不存在“abc”的引用&#xff…

GD32F103VE外部中断

GD32F103VE外部中断线线0~15&#xff0c;对应外部IO口的输入中断。它有7个中断向量&#xff0c;外部中断线0 ~ 4分别对应EXTI0_IRQn ~ EXTI4_IRQn中断向量&#xff1b;外部中断线 5 ~ 9 共用一个 EXTI9_5_IRQn中断向量&#xff1b;外部中断线10~15 共用一个 EXTI15_10_IRQn中断…

深入探索Vue.js核心技术与跨平台开发uni-app实战

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 前言 在当今Web应用不断…