从一个字符串数组中找出由A个0和B个1组成的最长子集的长度

从一个字符串数组中找出由a个0和b个1组成的最长子集的长度

在这个问题中,我们需要找到最多包含A个0和B1的最长子集。我们需要做的就是使用数组元素找到所有可能的子集,并找到包含最多 A 0 和 B1 的最长子集。

在本教程中,首先,我们将学习递归方法来解决问题。之后,我们将使用动态规划的方法来优化代码。

问题陈述 – 我们给出了一个包含 N 个二进制字符串的数组。此外,我们还给出了 A 和 B 整数。我们需要使用给定的二进制字符串创建最长的子集,使其不包含超过 A 0 和 B1。

示例

Input –  arr = {"101", "0", "101", "0", "1"}, A = 2, B = 1
Output – 3

说明

最长的子集是{ “0”, “0”, “1”},包含2个0和1个1。

Input –  arr = {"0", "101", "0", "1"}, A = 3, B = 3
Output – 3

说明

最长的子集是{“0”, “101”, “0”, “1”},3个0和3个1。

方法 1

在本节中,我们将学习一种使用递归的简单方法。我们将使用数组元素构造所有可能的子集,并找到包含 A 0 和 B 1 的最长子集。

算法

步骤 1 – 定义 countZeros() 函数来计算给定二进制字符串中零的总数。

步骤 1.1 – 将“count”变量初始化为零。

步骤 1.2 – 使用 for 循环遍历字符串。

步骤 1.3 – 如果第 i 个索引处的字符为“0”,则将“cnt”的值增加 1。

步骤 1.2 – 返回“cnt”变量的值。

步骤 2 – getMaxSubsetLen() 返回整数值并采用向量 arr、int A、int B 和索引作为参数。

步骤 3 – 定义函数内的基本情况。如果索引等于向量的大小,或者 A 和 B 的值均为零,则返回 0。

第 4 步 – 现在,计算索引处字符串中零的总数。

第 5 步 – 从字符串长度中减去 1 的总数,即可得出 1 的总数。

第 6 步 – 将“第一个”变量初始化为 0。

步骤 7 – 如果 0 和 1 的总数分别小于 A 和 B,则包含当前的二进制字符串。存储 1 + 函数递归调用的返回值。在进行递归调用时,从 A 和 B 中减去 0 和 1。

第 8 步 – 排除当前字符串并将结果值存储在“第二个”变量中。

第 9 步 – 返回第一个和第二个的最大值。

示例

#include using namespace std;// function to count the number of 0's in a stringint countZeros(string s){   // initialize count variable to 0   int count = 0;      // traverse the string   for (int i = 0; i < s.size(); i++){         // if the current character is 0, the increment count      if (s[i] == '0'){         count++;      }   }      // return count   return count;}// recursive function to find the maximum length of a subset of strings according to the given condition.int getMaxSubsetLen(vector arr, int A, int B, int index){   // base case   // if all the strings are traversed, or A + B becomes 0   if (index == arr.size() || A + B == 0){      return 0;   }      // total number of 0's in arr[index] string   int zero = countZeros(arr[index]);      // total number of 1's in arr[index] string   int one = arr[index].size() - zero;      // Stores the length of the subset, if arr[i] is included.   int first = 0;      // if the number of 0's and 1's in arr[index] is less than or equal to A and B, respectively, then include the string   if (zero <= A && one <= B){      first = 1 + getMaxSubsetLen(arr, A - zero, B - one, index + 1);   }      // Stores the length of the subset, if arr[i] is not included.   int second = getMaxSubsetLen(arr, A, B, index + 1);      // return the maximum of the first and second   return max(first, second);}// Driver Codeint main(){   vector arr = {"101", "0", "101", "0", "1"};   int A = 2, B = 1;   cout << "The maximum length of the subset consisting at most A 0s and B 1s is - " <<getMaxSubsetLen(arr, A, B, 0);   return 0;}

输出

The maximum length of the subset consisting at most A 0s and B 1s is - 3

时间复杂度 – O(2N),因为我们使用 N 个数组元素找到所有可能的子集。

空间复杂度 – O(1)

方法2

我们在本节中对上述方法进行了优化。我们使用动态规划的方法来解决这个问题。它存储前一个状态的结果,以降低问题的时间复杂度。

算法

第 1 步 – 定义 countZeros() 函数来计算特定二进制字符串中零的总数,就像我们在上述方法中所做的那样。

步骤 2 – 创建一个大小为 A x B x N 的 3 维向量来存储先前状态的结果。在列表中,当总 0 等于 A 且 1 等于 B 时,我们将在索引“I”处存储子集的长度。此外,将其作为 getMaxSubsetLen() 函数的参数传递。

第 3 步 – 按照我们在上述方法中所做的那样定义基本情况。

步骤 4 – 如果 dpTable[A][B][index] 的值大于 0,则表示状态已计算并返回其值。

第 5 步 – 计算当前字符串中 0 和 1 的总数。

第 6 步 – 获取包含和排除当前字符串后的结果值。

第 7 步 – 使用 max() 函数获取第一个和第二个的最大值,并将其存储在 dpTable[A][B][index] 中后返回

示例

#include using namespace std;// function to count the number of 0's in a stringint countZeros(string s){   // initialize count variable to 0   int count = 0;      // traverse the string   for (int i = 0; i < s.size(); i++){         // if the current character is 0, the increment count      if (s[i] == '0'){         count++;      }   }      // return count   return count;}// recursive function to find the maximum length of a subset of strings according to the given condition.int getMaxSubsetLen(vector array, int A, int B, int index, vector<vector<vector>> &dpTable){   // base case   if (index == array.size() || A + B == 0){      return 0;   }      // return if already calculated   if (dpTable[A][B][index] > 0){      return dpTable[A][B][index];   }      // total number of 0's in the current string   int zero = countZeros(array[index]);      // total number of 1's in the current string   int one = array[index].size() - zero;      // to store the length of the subset can be formed by including the current string   int first = 0;      // if the total number of 0's and 1's in the current string is less than or equal to A and B, respectively   if (zero <= A && one <= B){      first = 1 + getMaxSubsetLen(array, A - zero, B - one, index + 1, dpTable);   }      // to store the length of the subset can be formed by excluding the current string   int second = getMaxSubsetLen(array, A, B, index + 1, dpTable);      // store the maximum of the first and second, and return   return dpTable[A][B][index] = max(first, second);}int main(){   vector arr = {"101", "0", "101", "0", "1"};   int A = 2, B = 1;   vector<vector<vector>> dpTable(A + 1, vector<vector>(B + 1, vector(arr.size() + 1, 0)));   cout << "The maximum length of the subset consisting at most A 0s and B 1s is - " << getMaxSubsetLen(arr, A, B, 0, dpTable);   return 0;}

输出

The maximum length of the subset consisting at most A 0s and B 1s is - 3

时间复杂度 – O(A*B*N),因为我们需要填充 3D 列表才能获得结果。

空间复杂度 – O(A*B*N),因为我们使用 3D 列表进行动态规划方法。

以上就是从一个字符串数组中找出由A个0和B个1组成的最长子集的长度的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1444904.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月17日 21:59:53
下一篇 2025年12月13日 03:54:30

相关推荐

  • EF Core怎么配置复合主键 EF Core复合主键(Composite Key)配置方法

    EF Core 配置复合主键必须使用 Fluent API 的 HasKey 方法,不可用数据注解;需在 OnModelCreating 中指定匿名类型 lambda 表达式,如 od => new { od.OrderId, od.ProductId };字段须非空且不加任何主键特性。 EF…

    2025年12月17日
    000
  • C# 如何解析命令行参数 – 手动解析与System.CommandLine库

    C#解析命令行参数推荐System.CommandLine库,手动解析仅适用于简单场景;前者提供强类型、自动帮助、子命令和验证,后者需自行处理选项拆分、类型转换和错误提示。 在 C# 中解析命令行参数,有两种主流方式:手动解析(适合简单场景)和使用 System.CommandLine 库(推荐用于…

    2025年12月17日
    000
  • .NET中的文件和流(I/O)操作:高效处理数据读写

    .NET 中的 I/O 模型以 Stream 为核心,支持高效文件与数据流处理。1. Stream 是抽象基类,派生类包括 FileStream、MemoryStream 等,支持读写、缓冲与网络传输。2. 推荐使用 StreamReader/StreamWriter 逐行读写文本,避免内存溢出。3…

    2025年12月17日
    000
  • C#怎么分割字符串 C# String.Split方法的多种用法

    String.Split方法可用于按字符、字符串或多个分隔符分割字符串,支持限制数量和移除空项。1. 用单个字符如逗号分割字符串;2. 传入字符数组实现多分隔符拆分;3. 使用字符串数组作分隔符处理如”|||”;4. 添加StringSplitOptions.RemoveEm…

    2025年12月17日
    000
  • C# 怎么进行反射操作获取类型信息_C# 反射类型信息获取教程

    答案:C#反射可动态获取类型信息、创建对象并调用成员。使用typeof或GetType()获取Type对象,通过GetMethods()、GetProperties()等方法查询成员,配合BindingFlags访问非公共成员,利用Activator.CreateInstance()动态创建实例并调…

    2025年12月17日
    000
  • C#开发者如何学习算法?精选50个C#必会算法题与代码实现

    掌握基础排序、查找、递归、字符串数组操作及排列组合,是C#算法入门的关键。从冒泡排序建立编程思维,到快速排序理解分治;通过线性与二分查找熟悉数据定位技巧;利用递归解决阶乘、斐波那契等重复子问题;练习字符串反转、回文判断和两数之和提升日常编码能力;最后通过DFS与回溯生成全排列,培养深度搜索思维。每个…

    2025年12月17日
    000
  • C#的文件I/O操作是什么?如何读取和写入文本文件?

    C#的文件I/O操作通过System.IO命名空间实现,常用File.ReadAllText读取小文件内容为字符串,File.ReadAllLines按行读取为字符串数组,StreamReader逐行读取适合大文件;写入时File.WriteAllText覆盖写入,File.WriteAllLine…

    2025年12月17日
    000
  • .NET中的Span和Memory是什么?如何用它们实现高性能内存操作?

    Span和Memory是.NET高性能内存操作核心,Span在栈上操作连续内存,避免分配与GC,适用于局部高效切片;Memory可跨异步边界传递,支持堆持有,通过.Span获取Span进行高效处理。结合使用能减少复制与分配,提升吞吐,关键在于Span用于本地视图,Memory用于可传递引用。 &lt…

    好文分享 2025年12月17日
    000
  • C# 如何读取和写入文本文件_C# 文本文件读写操作指南

    答案:C#中读写文本文件常用File.ReadAllText/WriteAllText处理小文件,ReadAllLines/WriteAllLines按行操作,大文件推荐StreamReader/StreamWriter流式处理,并可指定编码如UTF8、GBK,根据文件大小和需求选择合适方法。 C#…

    2025年12月17日
    000
  • .NET怎么读取和写入文本文件_文本文件读写操作指南

    首先介绍.NET中常用的文本文件读写方法,包括使用File类进行小文件的读取和写入操作,如ReadAllText、ReadAllLines、WriteAllText和AppendAllText;接着说明处理大文件时应采用StreamReader和StreamWriter实现流式逐行读写以节省内存,并…

    2025年12月17日
    000
  • C# 如何在xml中存储和读取数组类型

    答案:使用XmlSerializer可将一维数组序列化为XML文件并反序列化读取,支持基本类型和公共自定义类数组,需注意类型匹配、访问权限及不支持多维数组。 在 C# 中,XML 不直接支持数组类型,但可以通过 序列化 和 反序列化 的方式将数组写入 XML 文件并读取回来。最常用的方法是使用 Xm…

    2025年12月17日
    000
  • C# 怎么使用 foreach 循环遍历数组_C# foreach 循环遍历数组教程

    foreach循环可安全遍历实现IEnumerable的集合;2. 语法为foreach(类型 变量 in 集合);3. 适用于数组、列表等一维集合;4. 循环变量是元素副本,不可修改原数组;5. 不支持逆序或修改集合长度。 在 C# 中,foreach 循环是一种简洁高效的方式来遍历数组中的每一个…

    2025年12月17日
    000
  • C# 如何解析命令行参数_C# 命令行参数解析方法详解

    答案:C#中处理命令行参数有多种方式,从Main方法接收基础参数,到手动解析简单场景,再到使用System.CommandLine或CommandLineParser等库实现高级功能,可根据项目复杂度选择合适方案。 在 C# 中处理命令行参数是开发控制台应用程序时的常见需求。正确解析命令行输入能让程…

    2025年12月17日 好文分享
    000
  • C# 中的索引器如何简化集合访问?

    索引器允许类通过方括号访问内部数据,如用整数或字符串作为索引封装数组或字典,提升代码可读性和封装性,支持参数类型重载且简化集合操作。 索引器(Indexer)让类像数组一样通过方括号 [] 直接访问内部数据,极大简化了集合操作。它常用于封装集合字段,提供更自然、直观的访问语法。 索引器的基本用法 定…

    2025年12月17日
    000
  • C#的enum关键字如何定义枚举?怎么使用?

    枚举通过为整型常量命名提升代码可读性和类型安全性,适用于表示固定选项(如状态、权限),支持指定值、位运算(配合[Flags]特性)及与字符串、数字的转换,广泛用于避免“魔法数字”并增强维护性。 C# 中, enum 关键字就是用来定义枚举的,它本质上是创建了一组命名的整型常量。这种方式让你的代码在表…

    2025年12月17日
    000
  • C#的字符串处理是什么?有哪些常用方法?

    C#字符串处理需关注不可变性带来的性能问题,频繁拼接应使用StringBuilder避免大量临时对象创建;常用方法如Substring、IndexOf、Replace、Trim、Split、Join及字符串插值等适用于不同场景;常见陷阱包括忽略null检查、错误比较方式和滥用正则,最佳实践包括使用S…

    2025年12月17日
    000
  • c语言中数组和指针的区别是什么_数组和指针有什么区别

    数组和指针的核心区别在于:数组是静态存储的同类型数据序列,而指针是动态存储内存地址的变量。1. 数组在声明时大小固定,不能改变;2. 指针可以指向不同的内存区域,具有动态性;3. 数组名代表整个数组,本质是符号,不可赋值,而指针是变量,可修改指向;4. 指针数组本质是数组,元素为指针,数组指针本质是…

    2025年12月17日 好文分享
    000
  • C#的String.Split方法如何分割字符串?

    c#的string.split方法核心作用是将字符串按指定分隔符拆分为字符串数组。1. 处理多个分隔符时,可通过传入char[]或string[]数组实现,如split(new char[] { ‘,’, ‘;’, ‘ ‘ })…

    2025年12月17日
    000
  • c语言string什么意思

    C 语言中的 string 类型是一个结构体,用于表示字符序列,具有自动内存管理和便利的字符串操作功能。它包含一个指向字符数组的指针、字符串长度和数组分配的最大长度。string 类型的好处包括自动内存管理、方便的字符串操作和安全性。要使用 string 类型,需要包含头文件 ,并使用 char *…

    2025年12月17日
    000
  • c语言中怎么输出数组

    在 C 语言中输出数组的方法有:使用循环逐个输出数组元素。使用数组指针简化循环,更灵活地访问元素。使用指针运算代替自增运算符。使用 printf 函数提供的格式说明符输出各种类型数组。 如何输出 C 语言中的数组 在 C 语言中,输出数组有多种方法。 使用循环: 这是最基础的方法,适合输出所有数组元…

    2025年12月17日
    000

发表回复

登录后才能评论
关注微信