J.学长陈梓豪的密码
题目描述:
一天,陈梓豪学长去注册账号。 陈梓豪学长发现,该网站的密码必须符合以下要求 至少应包括密码、、、这四种字符中有三种。 密码长度不小于 L 而且字符不多 R 个字符。 密码是只包含英文字母、数字和特殊符号的字符串。 特殊字符是指非大小写字母、数字、空格回车等不可见字符的可见字符,包括但不限于 “()_ *” 。
现在,陈末给了陈梓豪一个长度 N 的字符串 S ,学长陈梓豪想知道 S 串中有多少个子串是一个符合条件的密码。 请帮助陈梓豪统计合格的密码数量。
子串是指字符串中某一段的连续范围,如字符串 “aqwerdf” 来说,“aqw”, “qwe” 都是它的子串,而且 “aqr” 不是它的子串。
输入描述:
第一行输入三个正整数 N, L, R (1 <= N <= 105), (1 <= L <= R <= N),表示字符串的长度和合法字符的长度限制 。 第二行输入一个长度 N 的字符串 S 。 保证字符串只包括英文字母、数字和特殊符号。
输出描述:
一个整数表示有多少个子串是合法的密码
示例:
输入: 6 2 6 abcD2! 输出: 7 说明: abcD2 bcD2 cD2 D2! abcD2! bcD2! cD2!
思路: 先用一个 flag[5] 数组判断字符类型,flag[1] ~ flag[4] 表示四个字符,flag[0] 表示现有的字符类型。 要求合格的子串密码,我们可以使用快速和慢指针一步一步地通过字符串,每次添加一个,最终输出结果。
AC代码如下:
#include <bits/stdc .h> using namespace std; const int N = 1e5 5; int n, L, R; int flag[5]; char s[N]; ///判断字符的函数 int P(int x) {
if (s[x] >= 'A' && s[x] <= 'Z') return 1; if (s[x] >= 'a' && s[x] <= 'z') return 2; if (s[x] >= '0' && s[x] <= '9') return 3; ///其他字符返回4 return 4;
}
int main()
{
//初始化
scanf("%d %d %d\n", &n, &L, &R);
scanf("%s", s + 1);
//快慢指针
int l = 1, r = 0;
int ans = 0;
while (l <= n){
while (r - l + 1 <= R && r < n){
//右指针先右移一位后,判断是哪种字符
int p = P(r++);
//统计字符种类,若没有该字符,则加一,标记为已存在
if (flag[p] == 0)
flag[0]++;
//该字符数量加一
flag[p]++;
//若子串中字符种类有三种及以上,且符合合法字符的长度限制
if (flag[0] >= 3 && r - l + 1 >= L){
ans += min(n - r + 1, R - (r - l + 1) + 1);
break;
}
}
//右移左指针
int p = P(l++);
//若该种字符已存在,右移,字符种类减一
if (flag[p] == 1)
flag[0]--;
//字符数量减一
flag[p]--;
if (flag[0] >= 3 && r - l + 1 >= L)
ans += min(n - r + 1, R - L + 1);
}
printf("%d\n", ans);
return 0;
}