首先题目大致意思很简单,
就是两个要求:一、首尾字母符合要求,二、长度符合要求
那我们就有一个很朴素的想法就是暴力遍历。。但是看数据范围,
这种暴力解法是一定会tle的。那我们不妨换一种思想;
我们要统计有多少个子串符合要求,那也就是当我们遍历到c2的时候,看看前面有多少个符合要求的c1(长度要求),这如果再简化一下,就变成了统计c2之前有多少个c1,只不过需要判断一下长度;
这一下就有了解决问题的思路,用前缀和算法;
前缀和算法,故名思意就是一个统计前面所有的和的算法,它可以实现O(1)查找数组中某一位之前的和;
而我们这里不妨可以将问题简化为,遍历一遍s字符串,并且遇到一次c2,判断一下有多少个c1符合要求,并且加到结果中去;
#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using i64 = long long;
using namespace std;
int main()
{
int k;
cin >> k;
string s;
cin >> s;
char c1, c2;
cin >> c1 >> c2;
vector<int> prefix(s.size());//prefix是用来统计当前位置之前出现了多少个c1
long long sum = 0;
for (int i = 0, size = s.size(); i < size; ++i)
{
if (i)
{
//前缀和
prefix[i] += prefix[i - 1];
}
if (s[i] == c1)
{
++prefix[i];
}
if (s[i] == c2 && i - k + 1 >= 0)
{
//i - k + 1 是c1坐标 ,必须>=0
sum += prefix[i - k + 1];
}
cout << sum;
}
return 0;
}
这里s代表要进行操作的字符串,prefix数组用于表示前缀和数组
我们首先设一个for循环对字符串s进行遍历,然后在内部进行前缀和操作(如果下标大于0,就让后一位 += 前一位,这样就可以实现O(1)查找某一位之前的和),并且在遇到c1的时候就prefix[i] ++,如果遇到c2,我们需要进行判断;
判断的条件是啥?
题目中很明确的说了长度要求为k,那如果c2的下标为i,那么c1的下标经过计算应该为 i - k + 1;
那c1既然是在这个合法字符串中,那下标一定得 >=0
所以判断条件为 遍历到c2 且 c1下标>= 0
同时,如何计算出c2之前有多少个c1符合要求?
i - k + 1其实应该是擦着边过的要求,如图
对于这样一个黑长条当作 字符串s,那我里面随机出现的c1,c2可以是这样
如果对于中间某段,有这样的情况:
、
如果c2的下标为k,那么在c2左边,最靠近c2的一个c1坐标应该是 i - k + 1,这是最差情况,长度刚好为k,那之前还有若干个c1,所以我们可以在答案中加上prefix[i- k + 1] ;
其实也就是标标准准的前缀和了,统计该c1之前出现的c1个数。
希望我写的内容对大家有所帮助。谢谢大家!