String
题目大意:给一个字符串s,求它连续长度为 m*l 的子串s1,且s1可分为m个长度为 l 的子子串s2不相同的数量。
思路:
对比长度为 l 的字串是否相同,这里用到了BKDRHash,一般来说最高效的常用hash了,存m个(l * k , l * (k+1))的哈希值,比较是否相等,不等的话,窗口右移到最右端,依次比较即可,窗口滑动详解见代码。
Code:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#define inf 0x3f3f3f3f
#define getHashval(n, l) hv[n] - hv[n+l] * nbase[l]
using namespace std;
typedef long long int ll;
typedef unsigned long long ULL;
const int base = 31;
ULL hv[100007];
ULL nbase[100007];
map<ULL, int> hashmap;
int main()
{
int m,l,count;
string s;
nbase[0] = 1;
for(int i=1; i<=100000; i++)
nbase[i] = nbase[i-1] * base;
while (scanf("%d%d", &m, &l) != EOF) {
cin>>s;
count=0;
int len=(int)s.length();
hv[len]=0;
for(int i=len-1;i>=0;i--) //反向存
hv[i]=hv[i+1]*base+s[i];
int end=len-m*l; //规定结束范围
for(int i=0;i<l&&i<=end;i++){ // 窗口A,长度为m*l,在输入字符串上滑动,每次滑动1个字符,可以看到len-m*l+1个字串
hashmap.clear();
for(int j=i;j<i+m*l;j+=l) // 将长度为m*l的串,切割为长度为l的m个子串,分别将各个子串的哈希值放入hashmap集合
hashmap[getHashval(j, l)]++;
if(hashmap.size()==m)
count++;
int end2=len-m*l-l;
for (int j=i;j<=end2;j+=l) { // 窗口B,长度为m*l,开始与窗口A重合,每次向右滑动l个字符,到窗口右边与字符右边对齐为止
ULL temp = getHashval(j, l);
hashmap[temp]--;
if(hashmap[temp]==0)
hashmap.erase(temp);
hashmap[getHashval(j+m*l,l)]++;
if(hashmap.size()==m)
count++;
}
}
cout<<count<<endl;
}
return 0;
}