给出一个字符串和一个子字符串,以及起点和终点的索引,我希望能够找到该子字符串在绑定中出现的次数。例如,给定字符串“ 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条指令。
答案 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,因此基本思想是:
AC
,因此在的C
索引处标记 1 当您在字符串中匹配AC
时> arr 。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秒内完成所有测试用例。