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