计算每个字符出现频率为偶数且有一个例外的子字符串
在此问题中,我们将计算给定字符串中所有字符出现频率为偶数或任何单个字符出现频率为奇数的子字符串的数量。
我们将使用位掩码技术来解决这个问题。在位掩码中,二进制字符串的每个位代表字符。
问题陈述 - 我们给出了一个长度为 N 的字符串 alpha。还给出了 'a' <= alpha[i] <= 't'。我们需要计算所有字符都是偶数频率的子字符串的数量,或者只有一个字符是奇数频率而其他字符是偶数频率的子字符串的数量。
示例
输入
alpha = "pqq";
输出
5
说明- 有效子字符串为 pqq、p、q、q 和 qq。
输入
alpha = "mnbn";
输出
5
解释- 有效子字符串为 nbn、m、n、b 和 n。
方法 1
此方法使用位掩码来计算包含所有偶数频率字符或仅包含一个奇数频率字符的子字符串的数量。
逻辑 - 当我们对两个相同的整数进行异或时,结果为 0。
因此,我们将遍历字符串,并对每个字符值与初始位掩码值进行异或。如果之前出现过相同的位掩码,我们可以说子字符串包含所有具有偶数频率的字符,因为掩码的差为 0。此外,我们将添加和删除每个字符,以计算包含具有奇数频率的单个字符的子字符串。
算法
步骤 1 - 初始化大小为 220 的矩阵列表。
步骤 2 - 用 0 初始化"bitMask",表示初始掩码,用 0 初始化"cnt",以存储有效子字符串的数量。
步骤 3 - 用 1 初始化矩阵[0],因为空字符串始终有效。
步骤 4 - 开始遍历字符串。
步骤 5- 将 1 按字符值左移,并将其与位掩码值进行异或。这意味着我们将当前字符添加到掩码中。
步骤 6 - 将矩阵列表中相同位掩码的数量添加到"cnt"。例如,在"acbbe"字符串中,第 1 个和第 3 个索引处的位掩码变得相同。因此,我们可以获取"bb"子字符串。
步骤 7 - 使用循环进行 0 到 20 次迭代。在每次迭代中,将 1 左移 p,并将其与位掩码进行异或以从子字符串中删除字符。再次将先前出现的相同掩码的数量添加到"cnt"变量中。
步骤 8 - 增加列表中当前位掩码的值。
步骤 9 - 返回"cnt"值。
示例
#include <bits/stdc++.h> using namespace std; vector<int> matrix; long long getSubStrings(string &alpha) { matrix.resize(1 << 20); long long bitMask = 0, cnt = 0; // 空掩码的一种可能方法 matrix[0] = 1; for (auto c : alpha) { // 更改 char - 'a' 值处的位掩码 bitMask ^= 1 << (c - 'a'); // 获取具有相同掩码的有效子字符串 cnt += matrix[bitMask]; // 遍历所有可能的掩码 for (int p = 0; p < 20; p++) { // 更改掩码并将有效子字符串的数量添加到 cnt cnt += matrix[bitMask ^ (1 << p)]; } // 更新掩码的频率 matrix[bitMask]++; } return cnt; } int main() { string alpha = "pqq"; cout << "根据问题陈述,子字符串的总数为 " << getSubStrings(alpha); return 0; }
输出
根据问题陈述,子字符串的总数为 5
时间复杂度 - 遍历字符串的 O(N)。
空间复杂度 - O(2M),其中 M 是字符串中的唯一字符。
程序员可以通过获取每个子字符串并根据问题陈述检查子字符串是否有效来解决问题。但是,位掩码是解决此类问题的最佳技术。