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

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

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

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

问题描述 − 我们得到一个包含N个二进制字符串的数组。同时,我们给出了整数A和B。我们需要使用给定的二进制字符串创建最长的子集,使其不超过A个0和B个1。

示例

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()函数来计算给定二进制字符串中的0的总数。

  • 步骤1.1 − 将’count’变量初始化为0。

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

  • 步骤1.3 − 如果第i个索引处的字符是’0’,则将’cnt’的值增加1。

  • 步骤1.4 − 返回’cnt’变量的值。

  • 步骤2 − getMaxSubsetLen()返回整数值,并且带有vector arr、int A、int B和index作为参数。

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

  • 步骤4 − 现在,计算索引处字符串中0的总数。

  • 步骤5 − 从字符串长度中减去1的总数,以找到1的总数。

  • 步骤6 − 将’first’变量初始化为0。

  • 步骤7 − 如果0和1的总数都小于A和B,则包括当前的二进制字符串。存储1加上对函数的递归调用的返回值。在进行递归调用时,从A和B中减去0和1。

  • 步骤8 − 排除当前的字符串,并将结果值存储在’second’变量中。

  • 步骤9 − 返回first和second中的最大值。

示例

#include <bits/stdc++.h>
using namespace std;
// function to count the number of 0's in a string
int 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<string> 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 Code
int main(){
   vector<string> 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的三维向量,用于存储前一个状态的结果。在列表中,我们将在索引’I’处存储当总零等于A且1个等于B时的子集长度。同时,将其作为getMaxSubsetLen()函数的参数传递。

  • 步骤3 - 定义基本情况,就像我们在上述方法中所做的那样。

  • 步骤4 - 如果dpTable[A][B][index]的值大于0,则意味着状态已经计算过,返回其值。

  • 步骤5 - 计算当前字符串中零和一的总数。

  • 步骤6 - 得到包括和不包括当前字符串后的结果值。

  • 步骤7 - 使用max()函数从第一个和第二个中取得最大值,并在存储到dpTable[A][B][index]后返回它。

示例

#include <bits/stdc++.h>
using namespace std;
// function to count the number of 0's in a string
int 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<string> array, int A, int B, int index, vector<vector<vector<int>>> &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<string> arr = {"101", "0", "101", "0", "1"};
   int A = 2, B = 1;
   vector<vector<vector<int>>> dpTable(A + 1, vector<vector<int>>(B + 1, vector<int>(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),因为我们需要填充一个三维列表来获取结果。

空间复杂度 – O(A*B*N),因为我们在动态规划方法中使用了三维列表。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程