找到所有包含偶数个 1 且其反转也出现在给定字符串中的子字符串
在这个问题中,我们需要准备给定二进制字符串的一组唯一子字符串,如果它们包含偶数个 1 且它们的逆序也存在于该组中,则将它们从该组中删除。
我们可以用两种方法来解决这个问题。第一种方法是找到给定二进制字符串的所有子字符串,检查任何子字符串是否包含偶数个 1 以及它的逆序是否存在,并将逆序字符串从该组中删除。
另一种方法是比较给定字符串中奇偶校验位的总数。
问题陈述 - 我们给出了包含偶数个 1 的二进制字符串 str。我们需要准备给定二进制字符串的所有唯一子字符串的集合。之后,我们需要考虑从集合中包含偶数个 1 的长度为 n 的子字符串。如果子字符串的逆序也存在于该集合中,则从该集合中删除逆序子字符串。在输出中,打印包含唯一子字符串的集合的大小。
样例
输入
str = "01010"
输出
8
解释
唯一子字符串的集合为 [0, 1, 01, 010, 0101, 01010, 10, 101, 1010]。它总共包含 9 个子字符串。
0101 包含偶数个 1,并且它的逆序也存在于该集合中。因此,我们将从给定集合中删除它的逆序,即 1010。
最终集合为 [0, 1, 01, 010, 0101, 01010, 10, 101]。最终集合的大小为 8。
输入
str = '1010'
输出
7
解释
唯一子字符串为 [ 1, 10, 101, 1010, 0, 01, 010]。
对于任何包含偶数个 1 的字符串,其反向不在集合中。因此,我们不需要从集合中移除任何字符串。
最终输出与原始集合的大小相同。
输入
str = "111"
输出
3
唯一子字符串为 [1, 11, 111]。
包含偶数个 1 的字符串只有 11。
11 的反向也是 11。因此,我们不需要从集合中移除它,答案为 3。
方法 1
在此方法中,我们将创建一个集合,其中包含给定二进制字符串的所有唯一子字符串。之后,我们将遍历集合,如果我们发现包含偶数个 1 的字符串及其反向也存在于集合中,则我们将从集合中移除该字符串。
算法
步骤 1 - 定义名为 'subStrings' 的集合以存储唯一子字符串。
步骤 2 - 从第 0 个索引开始遍历字符串。在循环内,定义 'temp' 变量并用空字符串初始化。
步骤 3 - 使用另一个嵌套循环从 pth 索引开始迭代,并不断将 qth 字符附加到 'temp' 字符串。
步骤 4 - 将 'temp' 字符串插入集合。
步骤 5 - 使用迭代器遍历子字符串集合。
步骤 7 - 如果当前字符串中的 1 的总数是偶数,则反转 temp 字符串,并检查集合中是否存在反向 temp。
步骤 8 - 如果存在反向字符串,则移除该反向字符串。
步骤 9 - 返回集合的大小。
示例
#include <bits/stdc++.h> using namespace std; int getSize(string str) { // unordered set to store all substrings of a given string unordered_set<string> subStrings; // finding all substrings of a given string for (int p = 0; p < str.length(); p++) { string temp = ""; for (int q = p; q < str.length(); q++) { temp += str[q]; subStrings.insert(temp); } } // Check if any string contains an even number of 1's and its reverse exists in the set, then remove the string. for (auto it = subStrings.begin(); it != subStrings.end(); it++) { string temp = *it; // count the number of 1's in the string int cnt1s = 0; for (int i = 0; i < temp.length(); i++) { if (temp[i] == '1') cnt1s++; } // If count of 1's is even if (cnt1s % 2 == 0) { // reverse substring reverse(temp.begin(), temp.end()); // check if reverse exists in the set, remove it. if (temp != *it && subStrings.find(temp) != subStrings.end()) { subStrings.erase(temp); } } } return subStrings.size(); } int main() { string str = "01010"; cout << "The size of the set containing unique strings is " << getSize(str); return 0; }
输出
The size of the set containing unique strings is 8
时间复杂度 - O(N^4),因为 O(N^2) 用于遍历所有子字符串的集合,并且我们使用嵌套循环来遍历该集合。
空间复杂度 - O(N^2) 用于在集合中存储所有子字符串。
方法 2
在此方法中,我们将创建一个包含 3 个参数的列表:子字符串长度、偶数个 1 和奇数个 1。字符串的反向也将具有相同的长度、偶数个 1 和奇数个 1。如果我们将唯一对添加到列表,我们可以找到所有可以遵循列表条件的子字符串。
算法
步骤 1 - 定义矢量集合 'setList'
步骤 2 - 开始遍历字符串。此外,定义 cnt1s、even1s 和 odd1s 变量并用零初始化。
步骤 3 - 开始遍历子字符串。如果 qth 索引处的字符为 '1',则将 cnt1s 增加 1。
步骤 4 - 否则,如果 cnt1s 为偶数,则增加 even1s。否则,增加 odd1s。
步骤 5 - 获取子字符串的长度,并在创建列表后在集合中存储 len、even1s 和 odd1s。
步骤 6 - 返回列表的大小。
示例
#include <bits/stdc++.h> using namespace std; int getSize(string str) { // set to store the unique strings set<vector<int>> setList; // Iterate the string for (int p = 0; p < str.length(); p++) { // Required variables int cnt1s = 0, even1s = 0, odd1s = 0; for (int q = p; q < str.length(); q++) { // Count the counts of 1's if (str[q] == '1') { cnt1s++; } else { // If the count of 1's is even, increment even1s. Otherwise, increment odd1s. if (cnt1s % 2 == 0) { even1s++; } else { odd1s++; } } // get substring length int len = q - p + 1; // Insert the substring in the set vector<int> temp; temp.push_back(len); temp.push_back(even1s); temp.push_back(odd1s); setList.insert(temp); } } return setList.size(); } int main() { string str = "01010"; cout << "The size of the set containing unique strings is " << getSize(str); return 0; }
输出
The size of the set containing unique strings is 8
时间复杂度 - O(N^2),因为我们创建了所有子字符串。
空间复杂度 - O(N*N) 用于在集合中存储对。
对于初学者来说,第二种解决方案可能有点难以理解,但是如果我们说反向字符串具有相同的长度和奇偶校验位,那么它就很容易理解。第一种方法的时间复杂度要高得多。因此,最好使用第二种方法解决问题。