#子串查找

题目描述

这是一道模板题。

给定一个字符串 A 和一个字符串 B ,求 B 在 A 中的出现次数。A 和 B 中的字符均为英语大写字母或小写字母。

A 中不同位置出现的 B 可重叠。
输入格式

输入共两行,分别是字符串 A 和字符串 B 。
输出格式

输出一个整数,表示 B 在 A 中的出现次数。
样例
输入

zyzyzyz
zyz

输出

3

数据范围与提示

1 ≤ A , B 的长度 ≤ 1 0 6 , A 、 B 仅包含大小写字母。 1 \leq A, B 的长度 \leq 10 ^ 6 , A 、 B 仅包含大小写字母。 1A,B的长度106AB仅包含大小写字母。

分析

模版题,证明略

代码

#include
using namespace std;

const int x=17,M=1e7;
int a[M],b[M],h[M],ans=0;
char aa[M],bb[M];
int main(){
	scanf("%s%s",aa+1,bb+1);
	int m=strlen(aa+1),n=strlen(bb+1);
	
	a[0]=1;
	for (int i=1;i<=n;i++) a[i]=a[i-1]*x;
	
	for (int i=1;i<=m;i++) h[i]=h[i-1]*x+aa[i]-'A'+1;
	int s=0;
	for (int i=1;i<=n;i++) s=s*x+(bb[i]-'A'+1);
	for (int i=0;i<=m-n;i++) 
		if (s==h[i+n]-h[i]*a[n]) ans++;
		
	cout<<ans;
	
	return 0;
}

这里使用hash,这里给出递推式:
H ( C , i ) = H ( C , i − 1 ) ∗ x + c i   ( c i = C i − ′ A ′ + 1 ) H(C,i)=H(C,i-1)*x+c_{i}\ (c_i=C_i-'A'+1) H(C,i)=H(C,i1)x+ci (ci=CiA+1)
判断式:
H ( C ‘ ) = H ( C , i + n ) − H ( C , i ) ∗ x n H(C`)=H(C,i+n)-H(C,i)*x^n H(C)=H(C,i+n)H(C,i)xn
至此得出原理.

scanf("%s%s",aa+1,bb+1);
	int m=strlen(aa+1),n=strlen(bb+1);

指针原理,aa,bb是数组名,也是指针,strlen与scanf都与指针有关,可以使用指针运算读数.

	a[0]=1;
	for (int i=1;i<=n;i++) a[i]=a[i-1]*x;

递推计算幂,效率极高
当然,也可以对hash值取余,防止int溢出;

额外代码

#include
using namespace std;
int main() {
    string A, B;
    cin >> A >> B;
    int cnt = 0;
    for (auto iter = A.begin(); iter <= A.end() - B.size(); iter++) 
        if (equal(B.begin(), B.end(), iter)) cnt++;
    cout << cnt << endl;
    return 0;
}

此方法仍可以过,效率相比较hash低下,但简单易懂:
我们首先输入字符串 A 和字符串 B。然后使用 equal函数在 A 中搜索 B 的出现位置,具体做法是遍历 A 的每个字符迭代器,判断以该位置为起点的子串是否与 B 相等,如果相等则计数器加一。
在以上代码中,我们将字符串 B 视为一个字符序列,以 A 中每个字符的迭代器为起点,调用 equal 函数判断与 B 是否相等。

end

综上所述,模版题,证明略

你可能感兴趣的:(算法)