方法一:二分
思路:把下标记录到两个数组中,如何固定其中一个数组,在另一个数组中找下标距离大于等于k的个数有多少个。
代码:
#include<iostream>
#include <vector>
using namespace std;
int k;
char st,ed;
string p;
void solve()
{
cin >> k;
cin >> p >> st >> ed;
vector<int> ps, pe;
for (int i = 0; i < p.size(); i ++)
{
if(p[i] == st) ps.push_back(i);
if(p[i] == ed) pe.push_back(i);
}
long long ans = 0;
for (int i = 0; i < ps.size(); i ++)
{
int x = ps[i];
int X = x + k - 1;
int l = 0, r = pe.size() - 1;
while (l < r)
{
int mid = l + r >> 1;
if(pe[mid] >= X) r = mid;
else l = mid + 1;
}
if(pe[l] >= X) ans += pe.size() - l;
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
solve();
return 0;
}
方法二:前缀和
思路:使用s[i]表示前缀中给定首字母出现的次数(可以用t变量维护),遍历的同时当出现尾字母时,答案累加s[i - k + 1]。
代码:
int main()
{
scanf("%d\n%s %c %c", &k, str + 1, &st, &ed);
n = strlen(str + 1);
LL res = 0;
for (int i = 1, t = 0; i <= n; i++)
{
if (str[i] == st) t++;
s[i] = t;
if (i >= k && str[i] == ed) res += s[i - k + 1];
}
printf("%lld\n", res);
return 0;
}