【发布时间】:2015-07-12 17:12:14
【问题描述】:
给定一个二进制字符串 s,我们需要找到它的子字符串的数量,其中正好包含 k 个字符为 '1'。
例如:s = "1010" and k = 1, answer = 6。
现在,我在累积和数组上使用二进制搜索技术解决了这个问题。
我还使用了另一种方法来解决它。方法如下:
对于每个位置 i,找到以 i 结尾的所有子字符串包含 正好 k 个字符为 '1'。
要找到以 i 结尾的全部子串,其中恰好包含 k 个为 1 的字符,它可以表示为索引集 j,使得子串 j 到 i 恰好包含 k 个“1”。答案将是集合的大小。现在,要找到给定位置 i 的所有这样的 j,我们可以将问题改写为找到所有这样的 j
从 [1] 到 [j - 1] 的个数 = 从 1 到 i 的总个数 - [从 j 到 i 的总个数 = k]。
即从 [1] 到 [j - 1] 的个数 = C[i] - k
等于 C[j - 1] = C[i] - k,
其中 C 是累积和数组,其中 C[i] = 字符串从 1 到 i 的字符总和。 现在,问题很简单,因为我们可以通过计算总和为 C[i] - k 的所有前缀,使用等式找到 j 的所有可能值。
但我找到了这个解决方案,
int main() {
cin >> k >> S;
C[0] = 1;
for (int i = 0; S[i]; ++i) {
s += S[i] == '1';
++C[s];
}
for (int i = k; i <= s; ++i) {
if (k == 0) {
a += (C[i] - 1) * C[i] / 2;
} else {
a += C[i] * C[i - k];
}
}
cout << a << endl;
return 0;
}
在代码中,S 是给定的字符串,K 如上所述,C 是累积和数组,a 是答案。 我不知道使用乘法的代码到底在做什么。 有人能解释一下这个算法吗?
【问题讨论】:
-
我刚刚理解了k = 0部分,如果k = 0,由于c[i]是累积和等于i的出现次数,我们必须有(c[i] - 1)子串中相邻的零。因此,总和为零的可能子串的数量 = (c[i] - 1) * (c[i] - 1 + 1) / 2 = c[i] * (c[i] - 1) / 2,计算所有字符为零的字符串的可能子字符串的数量。
-
我想我也得到了另一部分。