如何在给定起点和终点的字符串中查找子字符串出现的次数?

时间:2019-03-26 11:22:46

标签: c++ string algorithm substring

给出一个字符串和一个子字符串,以及起点和终点的索引,我希望能够找到该子字符串在绑定中出现的次数。例如,给定字符串“ ACACTACG”,我想查找子字符串“ AC”的出现次数,从3到7(如果第一个索引为1)。上面的示例产生输出2。从3到7,我们有“ ACTAC”,其中子字符串“ AC”出现2次。我似乎无法用C ++编写代码;

这是AtCoder初学者竞赛122的问题C:https://atcoder.jp/contests/abc122/tasks/abc122_c

我实际上已对此进行了编码,但已超过了时间限制。我需要一个更简单的方法。

这是我为TLE结果提交的内容:

#include <iostream>

using namespace std;

int main()
{
    int N, Q;
    string s;
    cin >> N >> Q >> s;

    for(int i = 0; i < Q; i++)
    {
        int l, r;
        cin >> l >> r;
        if(l >= r)
        {
            cout << 0 << endl;
            break;
        }
        int count = 0;
        for(int j = l - 1; j < r; j++)
        {
            if(s[j] == 'A' && s[j + 1] == 'C' && j != r - 1)
            {
                count++;
                j++;
            }
        }
        cout << count << endl;
    }

    return 0;
}

做完一些数学运算后,我设法发现TLE的原因是因为我的代码大约有10 ^ 10条指令,而2秒的时间限制只能执行大约2 * 10 ^ 8条指令。

2 个答案:

答案 0 :(得分:2)

对于所有查询,字符串N都是相同的,并且您只在寻找模式AC。这意味着您可以预计算答案的查找表,并避免为每个查询迭代N。

自字符串开头以来,查找表将出现AC的次数。对于ACACTACG,应该是

A={0,1,1,2,2,2,3,3}

这有帮助,因为“ x和y之间的AC发生次数”与“ y之前的发生次数,除了x之前的发生次数”相同。此类表通常在您需要回答有关范围的问题时很有用

例如,要回答查询3,7,您需要计算A [7] -A [3] = 3-1 = 2。

答案 1 :(得分:0)

正如 Joni 所说,您可以创建一个 arr 之类的lookupArr。由于要匹配的模式的长度为2,因此基本思想是:

  • 首先创建一个长度为 n + 1 的数组,所有值均填充为 0
  • 第二,尝试在字符串 s 中匹配模式AC,因此在C索引处标记 1 当您在字符串中匹配AC时> arr
  • 通过这种方式,您将只对数组进行一次迭代,然后再回答任何查询
  • 对于每个查询,您可以在 O(1)时间内解决此问题,因为找到的总模式将为arr[r] - arr[l-1]
  • 注意,请确保您按照下面的代码中的说明查找部分重叠

希望这会有所帮助:

// This program is created by Ishpreet Singh
#include <iostream>
#include <string>
using namespace std;

int main()
{
  int n, q, l, r;
  string s;
  cin >> n >> q;
  cin >> s;
  // The lookUp Arr
  int arr[n + 1];
  arr[0] = arr[1] = 0;
  for (int i = 1; i < n; i++)
  {
    if (s.at(i - 1) == 'A' && s.at(i) == 'C'){
      arr[i + 1] = arr[i] + 1;
    }
    else{
      arr[i + 1] = arr[i];
    }
  }
  while (q--)
  {
    cin >> l >> r;
    int ans = arr[r] - arr[l - 1];
    // To Remove partial overlaps of AC, like s[l-1] = 'A' and s[l] = 'C'
    if (l > 1 && arr[l] == arr[l - 1] + 1){
      ans--;
    }
    cout << ans << endl;
  }
  return 0;
}

通过这种方式,您可以在 O(1) 时间内回答查询,因此代码的总体复杂度将为 O(Q) ,并会通过1秒内完成所有测试用例。