具有k个的总子串

时间:2015-07-12 17:12:14

标签: string algorithm

给定二进制字符串s,我们需要找到其子字符串的数量,其中包含恰好为“1”的k个字符。

例如:s =“1010”,k = 1,答案= 6.

现在,我使用二进制搜索技术在累积和数组上解决了它。

我还用另一种方法来解决它。方法如下:

  1. 对于每个位置i,找到以i结尾的总子串 正好是k为'1'的字符。

  2. 为了找到在i处结尾的总子串,其中包含正好为1的k个字符,它可以表示为索引j的集合,使得子串j到i包含正好k'1'。答案是集合的大小。现在,为了找到给定位置i的所有这样的j,我们可以将问题重新解释为找到所有j以便

  3. 从[1]到[j - 1]的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是答案。 使用乘法的代码是什么,我不知道。 有人能解释一下这个算法吗?

1 个答案:

答案 0 :(得分:1)

如果您看到计算C[i]的方式,C[i]表示i 1i+1 st 1之间的字符数

如果你举一个例子S = 1001000

                   C[0] = 1 
                   C[1] = 3 // length of 100
                   C[2] = 4 // length of 1000

所以出现疑问,为什么选择

说出你的K=1,然后你想找出只有一个1的子字符串,现在你知道在第一个1之后有两个零since C[1] = 3。所以子串的数量将是3,因为你必须包含这个1.

       {1,10,100}

但是当你来到第二部分时:C[2] =4

现在,如果您看到1000并且您知道可以制作4个子串(等于C [2])

     {1,10,100,1000}

并且你应该注意到C[1]-1之前有1个零。

因此,通过包含这些零,您可以创建更多子字符串,在这种情况下,包括0一次

      0{1,10,100,1000}
      => {01,010,0100,01000}

00一次

      00{1,10,100,1000}
      => {001,0010,00100,001000}

所以基本上你从C[i]开始制作1个子串,你可以在此之前追加i个零,并制作另一个C[i] * C[i-k]-1个子串。 i varies from 1 to C[i-k]-1(-1因为我们想留下最后一个)。

   ((C[i-k]-1)* C[i]) +C[i]
   => C[i-k]*C[i]