String (字符串哈希+滑动窗口)

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;
}


参考博客

猜你喜欢

转载自blog.csdn.net/weixin_43872264/article/details/107571742