【C++】ZZ1847- 解题精讲

【Horn Coding Studio】CPP编程专栏

题目

题目描述

给两个字符串S1,S2,求S2是否是S1的子串。

输入

输入两个字符串S1,S2。 1|S1|,|S2|1000001≤|S1|,|S2|≤100000

输出

若是则输出YES,反之输出NO。

样例输入 复制

sdabcad
dabcdc

样例输出 复制

NO

提示

来源

一点即通

新的知识点---------------》字符串哈希 学习笔记 - xiaomuyun - 博客园 (cnblogs.com)

 

这一道题由于数据有点水,于是有大聪明使用了如下代码:

#include <bits/stdc++.h>
using namespace std;
char s1[100001],s2[100001];
int main() {
    scanf("%s%s",&s1,&s2);
    puts((strstr(s1, s2) != NULL) ? "YES" : "NO");
    return 0;
}//《关于ac了这件事情》

当然这题我们需要使用更准确的方法,以达到o(1)复杂度,利益最大化!由于hash值可能会超出int,我们需要mod一个质数,还要定义一个基准值p,必须全部都是质数,不然……………………

我们需要一种特殊的哈希生成法则:

int hash=(hash1[ri]-1ll*hash1[le-1]*pre[ri-le+1])%mod;

hash1☞串,hash2☞子串,pre是一个数组。

 

现在就很esay了!

代码

ZZOJ     AC   

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int p=13131;
const int mod=1e9+7;
char s1[100005],s2[100005];
int hash1[100005],hash2[100006],pre[100005];
int idx(char ch) {
    return ch-'a'+1;
}
int main() {
    scanf("%s%s",s1+1,s2+1);
    int len1=strlen(s1+1);
    int len2=strlen(s2+1);
    pre[0]=1;
    for(int i=1; i<=len1; i++) {
        pre[i]=(1ll*pre[i-1]*p)%mod;
    }
    for(int i=1; i<=len1; i++) {
        hash1[i]=(1ll*hash1[i-1]*p+idx(s1[i]))%mod;
    }
    for(int i=1; i<=len2; i++) {
        hash2[i]=(1ll*hash2[i-1]*p+idx(s2[i]))%mod;
    }
    int ans=0;
    for(int i=1; i+len2-1<=len1; i++) {
        int le=i;
        int ri=i+len2-1;
        int hash=(hash1[ri]-1ll*hash1[le-1]*pre[ri-le+1])%mod;
        hash=(hash+mod)%mod;
        if(hash==hash2[len2]) {
            ans=1;
            break;
        }
    }
    if(ans) cout<<"YES";
    else  cout<<"NO";
    return 0;
}

 

posted @ 2022-06-18 23:06  冯子坤  阅读(29)  评论(0编辑  收藏  举报