#双指针 #快慢指针
题目描述
有n个数,和一个整数m。
现要从这n个数中选出一个连续子串,要求这个子串里面至少有k个数要大于等于m。
问一共能选出多少个子串(显然子串长度要大于等于k)。
输入描述
输入第一行是3个整数n、m、k。
输入第二行是n个整数,a1,a2,...,an,表示序列。
输出描述
输出一个整数表示答案。
样例输入
7 4 2
4 2 7 7 6 5 1
样例输出
18
题解:
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 9;
int a[N];
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m, k;
cin >> n >> m >> k;
for (int i = 1; i <= n; i++)
cin >> a[i];
int ans = 0;
for (int i = 1, j = 0, cnt = 0; i <= n; i++) {
while (i > j || (j + 1 <= n && cnt < k))
cnt += (a[++j] >= m);
if (cnt >= k)
ans += n - j + 1;
cnt -= (a[i] >= m);
}
cout << ans << endl;
return 0;
}
总结:
首先开一个数组存储这n个数。遍历数组进行赋值。
使用双指针i,j表示区间,通过for循环对双指针区间进行移动。
①当i > j ,即左指针的值大于右指针的值,显然这个区间不合法。或者右指针有向右移动的空间并且不满足条件k时,即(j + 1 <= n && cnt < k)。此时++j,使右指针向右移动,并且判断该值是否大于m,若满足条件就返回true,强制转换为1,使cnt+1。使 cnt += (a[++j] >= m);
②在执行①的过程中,当出现cnt的个数大于k,即满足题目要求时,此时答案子串的个数为末尾数组的值减去当前右指针的值,即ans += n - j + 1。(也就是:当前右指针为满足条件的最小区间,右边的都比它大,也就都满足条件。) 相应地,在右指针向右移的过程中,左指针也在向右移,若左指针所走过的值>m即满足条件,则令cnt -= (a[i] >= m);(也就是:减去之前包含在区间内满足条件的点,而现在不在了。)