题意:给一个字符串,给定n和m,字符串里最多有m个不同的字符,问长度为n的不同子串最多有几个
本题涉及到了一些基本的哈希。。。。
哈希的思路就是把字符转化成可以相加减的具体数字,举个例子。。。
判断字符串 "123132" 和 字符串 "213233"是否相等,是很容易做到的。。我们把他们当做数字来看,只需要看看这两个数字,a1是否等于 a2 就可以了,哈希的思路和这个也很相似
首先 我们把这m 个字符重新赋值一下,
char s[maxn];
ll num[maxn];
int zz = 0;
num[s[0]] = zz++;
memset(num,0,sizeof(num));
for(int i=1;i<len;i++)
{
if(num[s[i]] == 0)
num[s[i]] = zz ++;
}
重新复制之后,我们再把连续的字符串 变成一个连续 m 进制的数字(因为会有m个不同字符)
for(int i=0;i<=len-n;i++)
{
int sum = 0;
for(int j=0;j<n;j++)
sum = sum * zz + num[s[i + j]]; // 对某一串长度为n具体字符串赋值
}
有了 sum,我们只需判断 sum 是否出现过,就可以了。。。。
以下是 AC 代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long int
const int maxn = 16000003;
char s[maxn];
int has[maxn];
int num[300];
int n,m;
void init(char *s)
{
int len = strlen(s);
int zz = 0;
num[s[0]] = zz++;
for(int i=1;i<len;i++)
{
if(num[s[i]] == 0)
num[s[i]] = zz ++;
}
}
int gethas(int l,int r)
{
int sum = 0;
for(int i=l;i<=r;i++)
{
sum = sum * m + num[s[i]];
}
return sum;
}
int main()
{
while(~scanf("%d%d%s",&n,&m,s))
{
int ans = 0;
int len = strlen(s);
init(s);
for(int i=0;i<=len-n;i++)
{
int cnt = gethas(i, i+n-1);
if(!has[cnt])
{
ans ++;
has[cnt] = 1;
}
}
printf("%d\n",ans);
}
return 0;
}