力扣第416题 *** 分割等和子集 c++ 新题 动态规划 中的 01背包问题

2023-11-02 09:44

本文主要是介绍力扣第416题 *** 分割等和子集 c++ 新题 动态规划 中的 01背包问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目

416. 分割等和子集

中等

相关标签

数组   动态规划

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

示例 1:

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

示例 2:

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

提示:

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

思路一二都是基于动态规划来解释的。

不会的可以先去了解了解动态规划是什么,怎么做,模板为什么,等等

然后去了解纯01背包的问题。可以上B站搜,或者本站csdn搜索

这里提供B站视频

代码随想录 动态规划 理论基础icon-default.png?t=N7T8https://www.bilibili.com/video/BV13Q4y197Wg/?spm_id_from=333.337.search-card.all.click&vd_source=fa18c7bb110345953d1f71c2974a5da6代码随想录 01背包 解题方法icon-default.png?t=N7T8https://www.bilibili.com/video/BV1cg411g7Y6/?spm_id_from=333.788&vd_source=fa18c7bb110345953d1f71c2974a5da6代码随想录 01背包 进阶解法 icon-default.png?t=N7T8https://www.bilibili.com/video/BV1BU4y177kY/?spm_id_from=333.788&vd_source=fa18c7bb110345953d1f71c2974a5da6

思路和解题方法 一 (二维数组dp法)

  1. 首先,计算数组 nums 的元素和,并判断是否为奇数,如果是,则无法平分成两个子集,直接返回 false

  2. 计算目标和 target,即每个子集的和应该为 sum / 2,同时判断数组 nums 中的最大值是否大于 target,如果是,则无法平分,直接返回 false

  3. 初始化一个大小为 n * (target+1) 的二维数组 dp,其中 dp[i][j] 表示在前 i 个元素中是否能够找到一些元素的和等于 j

  4. 将第一列 dp[i][0] 全部初始化为 true,因为任何元素都可以不选,使其和为 0。

  5. 将第一行 dp[0][nums[0]] 初始化为 true,因为只有第一个元素可以被选中,使其和为 nums[0]

  6. 从第二个元素开始遍历数组 nums,对于每个元素 nums[i],从 1 到目标和 target 进行遍历,计算 dp[i][j] 的值。

  7. 如果当前元素的值 nums[i] 大于当前的和 j,则不能将该元素加入到和为 j 的子集中,因此 dp[i][j] 的值与 dp[i-1][j] 相等。

  8. 如果当前元素的值 nums[i] 小于等于当前的和 j,则可以将该元素加入到和为 j 的子集中。此时,需要考虑两种情况:选中当前元素或不选中当前元素。因此,dp[i][j] 的值等于 dp[i-1][j]dp[i-1][j-nums[i]]

  9. 循环结束后,返回 dp[n-1][target] 的值,表示在前 n 个元素中是否能够找到一些元素的和等于目标和 target

复杂度

        时间复杂度:

                O(n*target)

时间复杂度:

  • 初始化动态规划数组:O(n * target),其中 n 是数组的长度,target 是目标和的大小。
  • 动态规划过程中的两层循环:O(n * target)。

因此,总体时间复杂度为 O(n * target)。

        空间复杂度

                O(n*target)

 空间复杂度:

  • 动态规划数组:O(n * target),用于存储子问题的解。

因此,总体空间复杂度为 O(n * target)。

c++ 代码 一

class Solution {
public:bool canPartition(vector<int>& nums) {int n = nums.size();if (n < 2) {return false;}int sum = accumulate(nums.begin(), nums.end(), 0); // 计算数组元素的总和int maxNum = *max_element(nums.begin(), nums.end()); // 找到数组中的最大值if (sum & 1) { // 如果总和为奇数,则无法平分成两个子集return false;}int target = sum / 2; // 目标和为总和的一半if (maxNum > target) { // 如果最大值大于目标和,则无法平分return false;}vector<vector<int>> dp(n, vector<int>(target + 1, 0)); // 创建二维动态规划数组for (int i = 0; i < n; i++) {dp[i][0] = true; // 初始化第一列,表示任何元素都可以不选,使其和为0}dp[0][nums[0]] = true; // 初始化第一行,只有第一个元素可以被选中,使其和为nums[0]for (int i = 1; i < n; i++) { // 从第二个元素开始遍历数组int num = nums[i];for (int j = 1; j <= target; j++) { // 遍历目标和的范围if (j >= num) { // 如果当前和大于等于当前元素的值dp[i][j] = dp[i - 1][j] | dp[i - 1][j - num]; // 可选方案为选中当前元素或不选中当前元素} else { // 如果当前和小于当前元素的值dp[i][j] = dp[i - 1][j]; // 只能选择不选中当前元素}}}return dp[n - 1][target]; // 返回最后一个元素对应的状态,表示是否能够找到一些元素的和等于目标和}
};

思路和解题方法 二(压缩二维 一维)

  1. 首先,定义了一个类 Solution,其中包含了一个公有成员函数 canPartition,该函数接受一个整数数组 nums,并返回一个布尔值。

  2. 在函数内部,首先计算了数组 nums 中所有元素的和,并将结果存储在变量 sum 中。

  3. 接下来,通过判断 sum 是否为奇数,来确定是否可以平分数组。如果 sum 是奇数,则无法平分,直接返回 false

  4. 如果 sum 是偶数,说明可以进行平分。将 sum 除以 2 得到目标值 target,即每个子集的和应该为 target

  5. 初始化一个大小为 10001(为题目数据大小*长度 / 2) 的数组 dp,用于存储动态规划过程中的中间结果。数组 dp 的索引表示当前的和,数组的值表示是否可以组成该和。

  6. 接下来,使用两层循环遍历数组 nums 和目标值 target。外层循环遍历数组 nums,内层循环从 target 开始递减到当前元素的值 nums[i]

  7. 在内层循环中,更新数组 dp 的值。对于每个位置 j,比较 dp[j]dp[j-nums[i]] + nums[i] 的大小,取较大值作为 dp[j] 的新值。这表示在考虑当前元素 nums[i] 时,可以得到的最大和为 dp[j]

  8. 循环结束后,判断数组 dp 的最后一个元素 dp[target] 是否等于 target。如果是,则说明可以找到一个子集使其和为 target,返回 true;否则,返回 false

复杂度

        时间复杂度:

                O(n*target)

        时间复杂度为 O(n×target),其中 n 是数组 nums 的长度,target 是数组 nums 中所有元素的和的一半。因为在内层循环中,需要遍历从 targetnums[i] 的所有可能的和,所以时间复杂度是 O(target),外层循环需要遍历整个数组 nums,所以时间复杂度是 O(n),因此总的时间复杂度是 O(n×target)。

        空间复杂度

                O(target)

        这段代码的空间复杂度为 O(target),因为需要创建一个大小为 target+1 的数组 dp 来存储动态规划的中间结果。

c++ 代码 二

class Solution {
public:bool canPartition(vector<int>& nums) {int sum = accumulate(nums.begin(), nums.end(), 0); // 计算数组 nums 的所有元素的和if (sum % 2 == 1) { // 如果和为奇数,则无法平分成两个子集,直接返回 falsereturn false;}int target = sum / 2; // 计算目标和,即每个子集的和应该为 sum / 2vector<bool> dp(target + 1, false); // 初始化一个大小为 target + 1 的布尔型数组 dp,表示能否组成目标和dp[0] = true; // 初始状态:目标和为 0 时肯定可以组成for (int i = 0; i < nums.size(); ++i) { // 遍历数组 numsfor (int j = target; j >= nums[i]; --j) { // 从 target 开始递减到 nums[i]dp[j] = dp[j] || dp[j - nums[i]]; // 更新 dp[j] 的值}}return dp[target]; // 返回 dp[target] 的值,表示是否能够组成目标和}
};

觉得有用的话可以点点赞,支持一下。

如果愿意的话关注一下。会对你有更多的帮助。

每天都会不定时更新哦  >人<  。

这篇关于力扣第416题 *** 分割等和子集 c++ 新题 动态规划 中的 01背包问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/329747

相关文章

如何解决idea的Module:‘:app‘platform‘android-32‘not found.问题

《如何解决idea的Module:‘:app‘platform‘android-32‘notfound.问题》:本文主要介绍如何解决idea的Module:‘:app‘platform‘andr... 目录idea的Module:‘:app‘pwww.chinasem.cnlatform‘android-32

C++中初始化二维数组的几种常见方法

《C++中初始化二维数组的几种常见方法》本文详细介绍了在C++中初始化二维数组的不同方式,包括静态初始化、循环、全部为零、部分初始化、std::array和std::vector,以及std::vec... 目录1. 静态初始化2. 使用循环初始化3. 全部初始化为零4. 部分初始化5. 使用 std::a

kali linux 无法登录root的问题及解决方法

《kalilinux无法登录root的问题及解决方法》:本文主要介绍kalilinux无法登录root的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,... 目录kali linux 无法登录root1、问题描述1.1、本地登录root1.2、ssh远程登录root2、

SpringBoot应用中出现的Full GC问题的场景与解决

《SpringBoot应用中出现的FullGC问题的场景与解决》这篇文章主要为大家详细介绍了SpringBoot应用中出现的FullGC问题的场景与解决方法,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录Full GC的原理与触发条件原理触发条件对Spring Boot应用的影响示例代码优化建议结论F

Python如何将大TXT文件分割成4KB小文件

《Python如何将大TXT文件分割成4KB小文件》处理大文本文件是程序员经常遇到的挑战,特别是当我们需要把一个几百MB甚至几个GB的TXT文件分割成小块时,下面我们来聊聊如何用Python自动完成这... 目录为什么需要分割TXT文件基础版:按行分割进阶版:精确控制文件大小完美解决方案:支持UTF-8编码

MySQL 中查询 VARCHAR 类型 JSON 数据的问题记录

《MySQL中查询VARCHAR类型JSON数据的问题记录》在数据库设计中,有时我们会将JSON数据存储在VARCHAR或TEXT类型字段中,本文将详细介绍如何在MySQL中有效查询存储为V... 目录一、问题背景二、mysql jsON 函数2.1 常用 JSON 函数三、查询示例3.1 基本查询3.2

MySQL中动态生成SQL语句去掉所有字段的空格的操作方法

《MySQL中动态生成SQL语句去掉所有字段的空格的操作方法》在数据库管理过程中,我们常常会遇到需要对表中字段进行清洗和整理的情况,本文将详细介绍如何在MySQL中动态生成SQL语句来去掉所有字段的空... 目录在mysql中动态生成SQL语句去掉所有字段的空格准备工作原理分析动态生成SQL语句在MySQL

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

Pyserial设置缓冲区大小失败的问题解决

《Pyserial设置缓冲区大小失败的问题解决》本文主要介绍了Pyserial设置缓冲区大小失败的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录问题描述原因分析解决方案问题描述使用set_buffer_size()设置缓冲区大小后,buf

resultMap如何处理复杂映射问题

《resultMap如何处理复杂映射问题》:本文主要介绍resultMap如何处理复杂映射问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录resultMap复杂映射问题Ⅰ 多对一查询:学生——老师Ⅱ 一对多查询:老师——学生总结resultMap复杂映射问题