算法练习-分割等和子集(思路+流程图+代码)

难度参考

        难度:困难

        分类:动态规划

        难度与分类由我所参与的培训课程提供,但需 要注意的是,难度与分类仅供参考。且所在课程未提供测试平台,故实现代码主要为自行测试的那种,以下内容均为个人笔记,旨在督促自己认真学习。

题目

        给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。注意:每个数组中的元素不会超过100数组的大小不会超过200

        示例1:输入:[1,5,11,5]

        输出:true

        解释:数组可以分割成[1,5,5]和[11]。

        示例2:

        输入:[1,2,3,5]

        输出:false

        解释:数组不能分割成两个元素和相等的子集。

        提示:1 <= nums.length <= 2008 1 <= nums[i] <= 100

思路

        1. 计算总和并判断:

        首先计算给定数组的所有元素之和。如果总和是奇数,那么不可能将数组分割成两个和相等的子集,因为两个相等的数加起来一定是偶数。如果总和是偶数,那么我们的目标是找到一个子集,其和为总和的一半。

        2. 动态规划数组的定义:

        定义一个二维数组`dp`,其中`dp[i][j]`表示从数组的前i个元素中选取一些,是否能够使它们的和等于j。由此,我们的目标转换为判断`dp[n][sum/2]`是否为真,其中n是数组的长度。

        3. 初始化:

        dp[i][0]为真,因为不选取任何元素时,任何前i个元素的和都可以为0。dp[0][j](除了`dp[0][0]`)为假,因为没有元素可以组成非零的j。

        4. 状态转移方:

        对于每个元素`nums[i]`和每个目标和j,我们有两种选择:不选取nums[i],这时dp[i][j] = dp[i-1][j];选取nums[i],这时dp[i][j] = dp[i-1][j-nums[i]]。因此,dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i]]。

        5. 结果:

        查看dp[n][sum/2]的值,如果为真,说明可以分割成两个和相等的子集。

示例

        假设nums = [1, 5, 11, 5],我们需要填充到dp[4][11]。

        初始化

        - sum = 22
        - target = sum / 2 = 11
        - 初始化dp表,dp[i][0] = true,其他为false。

        Step 1: i = 1, nums[i-1] = 1

        更新dp[1][j],其中j = 1时,dp[1][1] = true。

dp = [
[true, false, false, false, false, false, false, false, false, false, false, false],
[true, true,  false, false, false, false, false, false, false, false, false, false],
[true, false, false, false, false, false, false, false, false, false, false, false],
[true, false, false, false, false, false, false, false, false, false, false, false],
[true, false, false, false, false, false, false, false, false, false, false, false]
]

        Step 2: i = 2, nums[i-1] = 5

        我们可以更新dp[2][1], dp[2][5]为true。

dp = [
[true, false, false, false, false, false, false, false, false, false, false, false],
[true, true,  false, false, false, false, false, false, false, false, false, false],
[true, true,  false, false, false, true,  false, false, false, false, false, false],
[true, false, false, false, false, false, false, false, false, false, false, false],
[true, false, false, false, false, false, false, false, false, false, false, false]
]

        Step 3: i = 3, nums[i-1] = 11

        更新dp[3][1], dp[3][5], dp[3][11]为true。由于11正好是nums[i-1],所以dp[3][11] = true。

dp = [
[true, false, false, false, false, false, false, false, false, false, false, false],
[true, true,  false, false, false, false, false, false, false, false, false, false],
[true, true,  false, false, false, true,  false, false, false, false, false, false],
[true, true,  false, false, false, true,  false, false, false, false, true, false],
[true, false, false, false, false, false, false, false, false, false, false, false]
]

        Step 4: i = 4, nums[i-1] = 5

        最后一行考虑所有数字。我们更新dp[4][j]。由于nums[3] = 5,我们可以更新dp[4][6], dp[4][10], dp[4][11]等。

        最终状态(部分更新示例):

dp = [
[true, false, false, false, false, false, false, false, false, false, false, false],
[true, true,  false, false, false, false, false, false, false, false, false, false],
[true, true,  false, false, false, true,  false, false, false, false, false, false],
[true, true,  false, false, false, true,  false, false, false, false, true, false],
[true, true,  false, false, false, true,  true,  false, false, false, true, true]
]

        注意:由于空间限制,上面的dp表没有展示所有中间步骤的更新。在实际操作中,你会发现dp[i][j]的更新依赖于前一行的结果,以及当前行之前的结果(如果j >= nums[i-1])。

        结果

        最终,我们关注的是dp[4][11]的值,它是true。这意味着可以将数组[1, 5, 11, 5]分割成两个和为11的子集,例如[1, 5, 5]和[11]。因此,canPartition函数返回true。

梳理

                实际上,"分割等和子集"问题不是一个经典的0-1背包问题的变种。

        针对"分割等和子集"问题,我们可以使用以下递推公式来求解:

        假设给定的数组为nums,数组的元素和为sum。我们想在数组中找到一个子集,使得这个子集的和等于sum / 2。那么,我们需要考虑以下两种情况:

  1. 不选择当前元素nums[i],即dp[i][j] = dp[i-1][j]
  2. 选择当前元素nums[i],即dp[i][j] = dp[i-1][j-nums[i]]

        其中,dp[i][j]表示从数组nums[0, i-1]下标范围内选取若干个元素,使得它们的和等于j。那么,我们可以得到递推公式:

dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i]]

        其中,dp[i][j]表示从前i个元素中,是否存在一个子集的和等于j。如果dp[i-1][j]true,则表示前i-1个元素中存在一个子集的和等于j,那么不选择当前元素nums[i]也可以满足条件,所以dp[i][j]true。如果dp[i-1][j-nums[i]]true,则表示前i-1个元素中存在一个子集的和等于j-nums[i],那么选择当前元素nums[i]后,该子集加上nums[i]的和等于j,也可以满足条件,所以dp[i][j]true

        这样,我们可以使用动态规划的方式从前往后填充dp表格,直到填充完整个表格。最终,dp[n][sum/2]的值表示是否存在一个子集的和等于原数组和的一半,如果为true,则表示可以分割成两个和相等的子集;如果为false,则表示无法分割成两个和相等的子集。

代码

#include <vector>
#include <numeric> // 用于计算数组和
using namespace std;

bool canPartition(vector<int>& nums) {
    int sum = accumulate(nums.begin(), nums.end(), 0); // 计算数组总和
    if (sum % 2 != 0) return false; // 如果总和是奇数,则不能分割成两个和相等的子集
    int target = sum / 2;
    vector<vector<bool>> dp(nums.size() + 1, vector<bool>(target + 1, false));
    // 初始化
    for (int i = 0; i <= nums.size(); ++i) {
        dp[i][0] = true;
    }
    // 动态规划填表
    for (int i = 1; i <= nums.size(); ++i) {
        for (int j = 1; j <= target; ++j) {
            if (j - nums[i-1] >= 0) {
                // 选取这个元素或不选取这个元素
                dp[i][j] = dp[i-1][j] || dp[i-1][j-nums[i-1]];
            } else {
                // 不能选取这个元素
                dp[i][j] = dp[i-1][j];
            }
        }
    }
    return dp[nums.size()][target];
}
  • 时间复杂度: O(n * sum)

  • 空间复杂度: O(nums.size() * target)

打卡

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[AIGC] 深入理解 Java 虚拟机(JVM)的垃圾回收

深入理解 Java 虚拟机&#xff08;JVM&#xff09;的垃圾回收 一、是什么 Java 虚拟机&#xff08;JVM&#xff09;的垃圾回收&#xff08;Garbage Collection&#xff09;是一种自动内存管理机制&#xff0c;用于释放不再使用的对象所占用的内存空间。垃圾回收的目标是回收那…

【HTML】SVG实现炫酷的描边动画

前沿 今天闲来无事&#xff0c;看到Antfu大佬的个性签名&#xff0c;觉得还是非常炫酷的&#xff0c;于是也想要搞一个自己的个性签名用来装饰自己的门面&#xff0c;不过由于手写的签名太丑了&#xff0c;遂放弃。于是尝试理解原理&#xff0c;深入研究此等密法&#xff0c;终…

如何录制视频?让你的录制过程更加顺畅!

录制视频是现代社会不可或缺的技能之一&#xff0c;无论是工作还是生活&#xff0c;我们都需要学会如何录制和编辑视频&#xff0c;可是您知道如何录制视频吗&#xff1f;本文将介绍两种录制视频的方法&#xff0c;这两种方法各有特点&#xff0c;可以满足不同用户的需求。 如何…

Windows制作Ubuntu的U盘启动盘

概要&#xff1a; 本篇演示在Windows10中制作Ubuntu22.04的U盘启动盘 一、下载Ubuntu22.04的iso文件 在浏览器中输入https://ubuntu.com去Ubuntu官网下载Ubuntu22.04的iso文件 二、下载Ultraiso 在浏览器中输入https://www.ultraiso.com进入ultraiso官网 点击FREE TRIAL&a…

腾讯云4核8G12M服务器支持多少人在线?

4核8G服务器支持多少人同时在线访问&#xff1f;阿腾云的4核8G服务器可以支持20个访客同时访问&#xff0c;关于4核8G服务器承载量并发数qps计算测评&#xff0c;云服务器上运行程序效率不同支持人数在线人数不同&#xff0c;公网带宽也是影响4核8G服务器并发数的一大因素&…

最高频率的图形工作站应用配置推荐

如果你的计算机速度太慢&#xff0c;想买一台最快的图形工作站&#xff0c;大幅提高你的工作效率&#xff0c;从专业角度&#xff0c;这种图形工作站不是唯一的&#xff0c;原因是&#xff0c;不同的应用、不同的算法、不同计算规模&#xff0c;硬件配置有很大差异&#xff0c;…

书生开源大模型-第2讲-笔记

1.环境准备 1.1环境 先克隆我们的环境 bash /root/share/install_conda_env_internlm_base.sh internlm-demo1.2 模型参数 下载或者复制下来&#xff0c;开发机中已经有一份参数了 mkdir -p /root/model/Shanghai_AI_Laboratory cp -r /root/share/temp/model_repos/inter…

大数据信用风险检测,多久查一次比较好?

自从大数据技术的出现&#xff0c;就被广泛的运用到金融风控行业&#xff0c;逐渐成为不少银行和机构进行贷前风险排查的重要工具&#xff0c;大数据信用的重要性也日益的显现出来&#xff0c;那大数据信用风险检测&#xff0c;多久查一次比较好呢?本文为你详细讲讲。 大数据信…

[AudioRecorder]iPhone苹果通话录音汉化破解版-使用巨魔安装-ios17绕道目前还不支持

首先你必须有巨魔才能使用&#xff01;&#xff01; 不会安装的&#xff0c;还没安装的移步这里&#xff0c;ios17 以上目前装不了&#xff0c;别看了&#xff1a;永久签名 | 网址分类目录 | 路灯iOS导航-苹果签名实用知识网址导航-各种iOS技巧-后厂村路灯 视频教程 【Audio…

森林消防利器:智能高压森林应急消防泵

在森林火灾防控工作中&#xff0c;智能高压森林应急消防泵发挥着至关重要的作用。它是一种由高强度耐腐蚀材料加工制造而成的消防泵&#xff0c;具有体积小、重量轻、压力大、扬程高、流量大、输水距离远等优点&#xff0c;运行可靠&#xff0c;能够迅速扑灭森林火灾&#xff0…

SG-9101CB(可编程+105℃晶体振荡器)

SG-9101CB 系列是一款高精度可编程性的晶体振荡器&#xff0c;能够在0.67 MHz至170 MHz的频率范围内以1ppm的步长精确调整频率。这款振荡器支持宽范围的电源电压&#xff08;1.62 V至3.63V&#xff09;&#xff0c;并提供使能&#xff08;OE&#xff09;或待机&#xff08;ST&a…

Java学习第十七节之封装

封装 package oop.demo04;//类 private:私有 public class Student {//属性私有private String name;//名字private int id;//学号private char sex;//性别private int age;//年龄//提供一些可以操作这个属性的方法&#xff01;//提供一些 public 的 get&#xff0c;set 方法…

如何使用Net2FTP部署本地Web网站并实现远程文件共享

文章目录 1.前言2. Net2FTP网站搭建2.1. Net2FTP下载和安装2.2. Net2FTP网页测试 3. cpolar内网穿透3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 文件传输可以说是互联网最主要的应用之一&#xff0c;特别是智能设备的大面积使用&#xff0c;无论是个人…

做temu跨境电商,必读这五大秘诀!

随着互联网的飞速发展&#xff0c;电商行业呈现出前所未有的繁荣景象。新兴电商平台Temu成为了众多创业者的关注焦点。本文将为您解析如何在Temu电商蓝海项目中&#xff0c;从自身能力建设、了解市场环境到做好定位等方面&#xff0c;找到属于您的成功之路。 一、自身能力建设 …

【QCA6174】SDX12+QCA6174驱动屏蔽120/124/128信道修改方案

SDX12基线版本 SDX12.LE.1.0-00215-NBOOT.NEFS.PROD-1.39743.1 问题描述 对于欧洲国家来说,默认支持DFS信道,但是有三个信道比较特殊,是天气雷达信道,如下图所示120、124、128,天气雷达信道有个特点就是在信号可以发射之前需要检测静默15min,如果信道自动选择到了天气雷达…

原创!顶级SCI优化!一键实现ICEEMDAN-NRBO-BiLSTM-Attention多变量时间序列预测!以光伏数据集为例

声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 目录 数据介绍 模型流程 创新点 结果展示 完整…

C++ STL详解:set

目录 一、简介 1.1键值对 1.2树形结构的关联式容器 二、set 2.1set简介 2.2set内部常用接口 2.1set的构造函数 2.2set迭代器 2.3判空及增删查改 三、使用例子 一、简介 在前几篇文章中&#xff0c;已经学习了二叉搜索树&#xff0c;二map和set的底层就是<key, va…

数据采集三防平板丨三防平板电脑丨停车场应用

随着现代科技的不断发展&#xff0c;三防平板已经成为许多人工作和生活的必备工具。在停车场这个场景中&#xff0c;三防平板的应用可以大大提高停车场管理的效率和安全性。 停车场是现代城市交通管理的重要组成部分&#xff0c;它直接关系到城市交通的流畅和公共安全。停车场…

国图公考:为什么考编?应届生考编有优势吗?

当下公务员和事业编成为大部分人的选择&#xff0c;事业编考试和公务员考试对比有哪些优势?为什么考编? 1.竞争激烈程度 虽然每年报考事业编的人有很多&#xff0c;但是和公务员相比起来竞争并没有那么激烈。 2.考试难度 事业编和公务员在考试内容上有一定的差异&#xf…

深度学习基础——卷积神经网络(一)

卷积操作与自定义算子开发 卷积是卷积神经网络中的基本操作&#xff0c;对于图像的特征提取有着关键的作用&#xff0c;本文首先介绍卷积的基本原理与作用&#xff0c;然后通过编写程序实现卷积操作&#xff0c;并展示了均值、高斯与sobel等几种经典卷积核的卷积效果&#xff…