代码随想录算法训练营第三十五天 | 416. 分割等和子集

news2024/11/14 0:00:38

416. 分割等和子集  

  • 题目链接:力扣题目链接
  • 文章讲解:代码随想录 

  • 视频讲解:动态规划之背包问题,这个包能装满吗?| LeetCode:416.分割等和子集

给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

注意: 每个数组中的元素不会超过 100 数组的大小不会超过 200

示例 1:

  • 输入: [1, 5, 11, 5]
  • 输出: true
  • 解释: 数组可以分割成 [1, 5, 5] 和 [11].

示例 2:

  • 输入: [1, 2, 3, 5]
  • 输出: false
  • 解释: 数组不能分割成两个元素和相等的子集.

提示:

  • 1 <= nums.length <= 200
  • 1 <= nums[i] <= 100

思路

这道题目是要找是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

那么只要找到集合里能够出现 sum / 2 的子集总和,就算是可以分割成两个相同元素和子集了。

首先,本题要求集合里能否出现总和为 sum / 2 的子集。

那么来一一对应一下本题,看看背包问题如何来解决。

只有确定了如下四点,才能把01背包问题套到本题上来。

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

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

动规五部曲分析如下:

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

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

本题中每一个元素的数值既是重量,也是价值。

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

那么如果背包容量为target, dp[target]就是装满 背包之后的重量,所以 当 dp[target] == target 的时候,背包就装满了。

有录友可能想,那还有装不满的时候?

拿输入数组 [1, 5, 11, 5],举例, dp[7] 只能等于 6,因为 只能放进 1 和 5。

而dp[6] 就可以等于6了,放进1 和 5,那么dp[6] == 6,说明背包装满了。

2.确定递推公式

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

3.dp数组如何初始化

在01背包,一维dp如何初始化,已经讲过,

从dp[j]的定义来看,首先dp[0]一定是0。

如果题目给的价值都是正整数那么非0下标都初始化为0就可以了,如果题目给的价值有负数,那么非0下标就要初始化为负无穷。

这样才能让dp数组在递推的过程中取得最大的价值,而不是被初始值覆盖了

本题题目中 只包含正整数的非空数组,所以非0下标的元素初始化为0就可以了。

4.确定遍历顺序

在动态规划:关于01背包问题,你该了解这些!(滚动数组)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!

5.举例推导dp数组

dp[j]的数值一定是小于等于j的。

如果dp[j] == j 说明,集合中的子集总和正好可以凑成总和j,理解这一点很重要。

用例1,输入[1,5,11,5] 为例,如图:

416.分割等和子集2

最后dp[11] == 11,说明可以将这个数组分割成两个子集,使得两个子集的元素和相等。

方法一: 动态规划-卡哥版一维数组

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        if sum(nums) % 2 != 0:
            return False
        target = sum(nums) // 2
        dp = [0] * (target + 1)
        for num in nums:
            for j in range(target, num-1, -1):
                dp[j] = max(dp[j], dp[j-num] + num)
        return dp[-1] == target

方法二:动态规划(二维数组)

class Solution:
    def canPartition(self, nums: List[int]) -> bool:
        
        total_sum = sum(nums)

        if total_sum % 2 != 0:
            return False

        target_sum = total_sum // 2
        dp = [[False] * (target_sum + 1) for _ in range(len(nums) + 1)]

        # 初始化第一行(空子集可以得到和为0)
        for i in range(len(nums) + 1):
            dp[i][0] = True

        for i in range(1, len(nums) + 1):
            for j in range(1, target_sum + 1):
                if j < nums[i - 1]:
                    # 当前数字大于目标和时,无法使用该数字
                    dp[i][j] = dp[i - 1][j]
                else:
                    #如果某个物品的重量小于j,那就可以看该物品是否放入背包
                    #dp[i - 1][j]表示该物品不放入背包,如果在 [0, i - 1] 这个子区间内已经有一部分元素,使得它们的和为 j ,那么 dp[i][j] = true;
                    #dp[i - 1][j - nums[i]]表示该物品放入背包。如果在 [0, i - 1] 这个子区间内就得找到一部分元素,使得它们的和为 j - nums[i]。
                    dp[i][j] = dp[i - 1][j] or dp[i - 1][j - nums[i - 1]]

        return dp[len(nums)][target_sum]

方法三:动态规划(一维数组)

class Solution:
    def canPartition(self, nums: List[int]) -> bool:

        total_sum = sum(nums)

        if total_sum % 2 != 0:
            return False

        target_sum = total_sum // 2
        dp = [False] * (target_sum + 1)
        dp[0] = True

        for num in nums:
            # 从target_sum逆序迭代到num,步长为-1
            for i in range(target_sum, num - 1, -1):
                dp[i] = dp[i] or dp[i - num]
        return dp[target_sum]

心得收获 

这里有个点注意,在求target是要用//得到的是整数类型的数值,如果用/就会得到float类型的数值

方法二中,dp[i][j] = dp[i - 1][j] or dp[i - 1][j - nums[i - 1]]可以好好理解一下,刚开始我有点没有看明白怎么理解,其实就是对应了两种情况:

1.如果取当前的数字nums[i-1],就要看上一层的结果中dp[i - 1][j - nums[i - 1]]是否能够填满背包

2.如果不取当前数值,就要看dp[i - 1][j]是否刚好填满背包

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

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

相关文章

面向对象01:类和对象的创建

本节内容视频链接&#xff1a;面向对象04&#xff1a;类与对象的创建_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV12J41137hu?p63&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 1.类、对象定义及关系 类&#xff08;‌Class&#xff09;‌是一个模板或蓝图&#…

如何规避DDoS攻击带来的风险?服务器DDoS防御软件科普

DDoS攻击是目前最常见的网络攻击方式之一。其见效快、成本低的特点&#xff0c;使它深受不法分子的“喜爱”。对于未受保护的企业来说&#xff0c;每次DDoS攻击的平均成本为20万美元&#xff0c;当DDoS攻击汹涌而至&#xff0c;缺失详细的保护预案&#xff0c;企业很可能会陷入…

erlang学习:gen_server书上案例22.6练习题4

昨天没有输出Fun中的io的原因是因为在任务函数中没有调用Fun方法&#xff0c;相当于只传了Fun函数但是没有进行调用&#xff0c;因此没有执行Fun函数&#xff0c;所以控制台中没有进行io的输出&#xff0c;今天在add_job中调用了Fun方法并执行&#xff0c;所以输出了相应的io。…

图像数据处理22

五、边缘检测 5.4 Hough变换 该技术主要用于检测图像中的基本形状&#xff0c;如直线、圆、椭圆等。 Hough变换的基本原理 Hough变换的基本原理是将图像空间中的直线或曲线变换到参数空间中&#xff0c;通过检测参数空间中的极值点&#xff08;局部最大值&#xff09;&…

自制镜像(贫穷版)

在装了docker的机子root目录操作 mkdir -p docker-images/tomcat-image/ cd docker-images/tomcat-image/ 把这两个红框的拉到docker-images/tomcat-image/ vim Dockerfile #导入基础镜像 from centos:7 #定义作者 maintainer GGBond<2958458916qq.com&…

SpringCloudGateway重写负载均衡策略

背景 gateway中多实例请求转发&#xff0c;默认采用轮训转发策略。在有些场景下&#xff0c;某些请求想固定到某一台实例上&#xff0c;这里通过重写默认负载均衡策略的方式实现。 以下代码为&#xff0c;大文件分片上传&#xff0c;多实例场景&#xff0c;根据文件md5和实例…

OpenCV c++ 实现图像马赛克效果

VS2022配置OpenCV环境 关于OpenCV在VS2022上配置的教程可以参考&#xff1a;VS2022 配置OpenCV开发环境详细教程 图像马赛克 图像马赛克&#xff08;Image Mosaic&#xff09;的原理基于将图像的特定区域替换为像素块&#xff0c;这些像素块可以是纯色或者平均色&#xff0c…

行业智能化的“火车头效应”,由星河AI金融网络启动

相信大多数人都认可&#xff0c;在行业智能化的列车中&#xff0c;金融是毋庸置疑的“火车头”。 有数据显示&#xff0c;目前AI整体渗透率只有4%&#xff0c;不同行业的AI渗透度有极大差异。其中&#xff0c;金融由于数字基础好&#xff0c;拥抱新技术的意愿强烈&#xff0c;成…

QT中通过Tcp协议的多线程的文件传输(服务器)

首先新建一个项目命名为SendClientSever 因为要进行网络通信&#xff0c;在pro文件的第一行代码中添加network 一、窗口设计 拖一个Widget里面放入label,lineEdit,pushbutton&#xff0c;名称如图修改 程序设计 子线程recvfile类 新建一个类用来执行子线程 将新建的类的头…

2-74 基于matlab的图像k-means聚类GUI

基于matlab的图像k-means聚类GUI&#xff0c;可对彩色图像进行Kmeans和meanshift进行聚类分析&#xff0c;生成最后的聚类图像以及聚类中心的迭代轨迹。程序已调通&#xff0c;可直接运行。 2-74 matlab GUI - 小红书 (xiaohongshu.com)

如何使用Python实现招聘数据的ftree算法可视化分析?大数据实战指导

&#x1f393; 作者&#xff1a;计算机毕设小月哥 | 软件开发专家 &#x1f5a5;️ 简介&#xff1a;8年计算机软件程序开发经验。精通Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等技术栈。 &#x1f6e0;️ 专业服务 &#x1f6e0;️ 需求定制化开发源码提…

【JavaEE】线程安全性问题,线程不安全是怎么产生的,该如何应对

产生线程不安全的原因 在Java多线程编程中&#xff0c;线程不安全通常是由于多个线程同时访问共享资源而引发的竞争条件。以下是一些导致线程不安全的常见原因&#xff1a; 共享可变状态&#xff1a;当多个线程对共享的可变数据进行读写时&#xff0c;如果没有适当的同步机制&…

目标 CDC实例数据库更改密码,预定启动报错SQL 错误代码为“-30082”。SQL 状态为:08001。

更改完CDC目标端实例密码后&#xff0c;登录MC更新存储器密码&#xff0c;存储器可正常连接&#xff0c;启动预定报错如下&#xff1a; 源 IBM Data Replication 未获授权&#xff0c;无法复制到该目标。 登录认证失败。 发生 SQL 异常。SQL 错误代码为“-30082”。SQL 状态…

区块链知识体系fisco-bcos实战

文章目录 一、区块链发展概述及类型和特征1.1 区块链的概念1.2 区块链的起源1.3 区块链的发展历程1.4 区块链的类型和特征 二、区块链的常见技术架构2.1 技术架构2.2 核心技术 三、区块链的常见应用3.1 生态环境监测3.2 医疗废弃物追踪解决3.3 区块链在电子政务领域的应用3.4 在…

前端宝典十三:node网络详解Tcp/IP/Http及网络安全防御

讨论网络相关的问题前&#xff0c;我们首先看一下从浏览器输入 URL 到显示前端页面的流程&#xff0c;首先从TCP的应用层、传输层、网络层、数据链路层开始看&#xff1a; 一、应用层、传输层、网络层、数据链路层 以下是从浏览器输入 URL 到显示前端页面的流程顺序解析&…

android 实现简易音乐播放器

音乐App 源代码 &#xff1a; 简易音乐APP源代码 1、简介 一个简易的音乐APP&#xff0c;主要练习对四大组件的应用。感兴趣的可以看看。 播放界面如下&#xff1a; 歌曲列表界面如下&#xff1a; 项目结构如下&#xff1a; 接下来将对代码做详细介绍&#xff1a; 2、Musi…

class_3:数据类型/交互模式/ input输入

获取字符串长度 #获取字符串长度 s "hello world!" print(len(s)) print(len("hello")) #根据索引取字符 print(s[0]) print(s[11]) #type a 10 b True c 1.0 d None #空值类型 print(type(a)) print(type(b)) print(type(c)) print(type(d))命令行模…

大型物流运输无人机技术详解

随着科技的不断进步和电子商务的蓬勃发展&#xff0c;大型物流运输无人机作为未来物流体系的重要组成部分&#xff0c;正逐步从概念走向实际应用。这类无人机以其超大的载重能力、高效的运输效率和广泛的覆盖范围&#xff0c;为解决远距离、大批量货物运输难题提供了创新方案。…

【Datawhale AI夏令营第五期】 CV方向 Task01学习笔记 YOLO方案baseline

【Datawhale AI夏令营第五期】 CV方向 Task01学习笔记 YOLO方案baseline 第四期给我的体验相当不错&#xff0c;于是我又冲动报名了第五期。这次比第四期的AIGC和大模型应用都要上强度。 CV这边进度拉得快&#xff0c;Task01都发布了。一看&#xff0c;好家伙&#xff0c;老朋…