KMP&&哈希算法

KMP算法

KMP算法是一种字符串匹配算法,用于匹配模式串P在文本串S中出现的所有位置。

例如S=“ababac”,P="aba",那么出现的所有位置是1 3

KMP算法将原本O(n^2)的字符串匹配算法优化到了O(n),其精髓在于next数组,next数组表示此时模式串下标失配时应该移动到的位置,(每次下标失配时,就是i!=j了,j=next[j-1])也表示最长的相同真前后缀的长度。

字符串“aba”这个例子来说的话,前缀(从左往右数)有:a,ab,aba(因为aba与原字符相等,所以不是真前缀)后缀(从右往左):a,ba,aba

字符串aba 

a的真前缀真后缀为0  ab的真前缀为a真后缀为b,所以也为0  aba的最长真前缀真后缀为a(长度设为1)所以aba的真前缀真后缀为1

字符串ababac

abab 的真前缀为 a,ab,aba真后缀有b,ab,bab所以最长真前后缀为ab,即为2

ababa 的真前缀有 a,ab,aba,abab,真后缀有a,ba,aba,baba,所以最长真前后缀为aba,即为3

计算next数组(next数组仅与模式串P有关)的方式就是P自己去匹配自己

KMP算法模板

int[] next=new int[p.length];
next[0]=0;
for(in i=1,j=0;i<p.length;i++){

    while(j>0&&p[j]!=p[i]){
        j=next[j-1];//不断匹配i,j直到p[i]==p[j]或者j==0
    }
    if(p[i]==p[j]){
        j++;
         next[i]=j;
    }
   
}

通过next数组进行匹配

for(int i=0,j=0;i<n;i++){

    while(j>0&&s[i]!=p[j])j=next[j-1];
    if(s[i]==p[j])j++;
    if(j==m)//匹配成功一次
}    

 字符串Hash算法

(基于进制的)字符串Hash本质上时一个用数字表示一段字符串,从而降低字符串处理的复杂度。

这个数字是一个很大的数字,采用long类型,还需要一个进制数base,用于规定这个数字的进制

Hash数组h[i]表示字符串s[1~i]的Hash值,采用类似前缀和的形式以便求出任意一个字串的Hash值。

(字符串转化成为数字)

字符串Hash初始化

long base=131;//base一般为一个质数(进制数)

long h[N];//h[i]表示s[1~i]的Hash(类似前缀和)

char s[N];//我们的字符串

for(int i=1;i<=n;++i) h[i]=h[i-1]*base+s[i]-'A'+1;//s[i]-‘A’+1表示字符串在我们字母表中的位置

获取字串s[1]~s[r]的Hash

long getHash(int l,int r){

        return  h[r]-h[l-1]*b[r-l+1];//b[i]表示base的i次方(预处理)

}

  例题实战

斤斤计较的小 Z

题目描述

小 Z 同学没天都喜欢斤斤计较,今天他又跟字符串杠起来了。

他看到了两个字符串 S1 S2 ,他想知道 S1 在 S2 中出现了多少次。

现在给出两个串 S1,S2(只有大写字母),求 S1 在 S2 中出现了多少次。

输入描述

共输入两行,第一行为 S1,第二行为 S2。

输出描述

输出一个整数,表示 S1 在 S2 中出现了多少次。

输入输出样例

示例1

输入

LQYK
LQYK

输出

1

 代码

kmp实现
​

public class jinjinjijiao {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner scan=new Scanner(System.in);
		char[] arr1=scan.next().toCharArray();
		char[] arr2=scan.next().toCharArray();
		int len1=arr1.length;
		int len2=arr2.length;
		int[] next=new int[len1];
		for(int i=1,j=0;i<len1;i++) {
			while(j>0&&arr1[i]!=arr1[j]) {
				j=next[j-1];
			}
			if(arr1[i]==arr1[j]) {
				j++;
			}
			next[i]=j;
		}
		int ans=0;
		for(int i=0,j=0;i<len2;i++) {
			while(j>0&&arr1[j]!=arr2[i]) {
				j=next[j-1];
			}
			if(arr1[j]==arr2[i]) {
				j++;
			}
			if(j==len1) {
				ans++;
				j=0;
			}
			
		}
		System.out.println(ans);
	}

}

​
Hash实现
package shiti;
import java.util.*;
public class Hash {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner scan=new Scanner(System.in);
		char[] arr1=scan.next().toCharArray();
		char[] arr2=scan.next().toCharArray();
		int m=arr1.length;
		int n=arr1.length;
		long[] h=new long[n+1];
		long[] s=new long[n+1];
		long res=0;
		long base=131;
		for(int i=0;i<m;i++) {//先求arr1的hash值
			res=res*base+(arr1[i]-'A'+1);
		}
		s[0]=1;
		for(int i=1;i<=n;i++) {
			h[i]=h[i-1]*base+(arr2[i-1]-'A'+1);
			s[i]=s[i-1]*base;
			
		}
		int ans=0;
		for(int i=1;i+m-1<=n;i++) {
		long sum=h[i+m-1]-h[i-1]*s[m];
			if(sum==res)
				ans++;
		}
		
		System.out.println(ans);
	}

}

  • 30
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
字符串匹配算法是一种用来查找一个字符串(即目标串)在另一个字符串(即模式串)中的出现位置的算法。其中,KMP算法是一种比较常用的字符串匹配算法。 KMP算法的核心思想是通过利用模式串中已经匹配过的信息,来尽量减少目标串和模式串的比较次数,从而提高匹配效率。它利用一个最长公共前缀和最长公共后缀数组,记录模式串中已经匹配成功的前缀和后缀的长度。通过根据这些信息来移动模式串的位置,避免不必要的比较。 而字符串哈希算法是一种将字符串映射为一个较短的固定长度的数值的算法。通过对字符串的每个字符进行一系列运算,如求幂、取模等,最终得到一个哈希值。这个哈希值可以代表该字符串的特征,不同字符串的哈希值一般不会相同。 字符串哈希算法的主要作用是将字符串转化为一个定长的数字,方便在数据结构中进行比较和存储。在字符串匹配中,使用哈希算法可以将目标串和模式串转换为哈希值,然后比较哈希值是否相等来判断是否匹配。由于比较哈希值的时间复杂度较低,使用字符串哈希算法可以提高匹配效率。 总的来说,字符串匹配算法和字符串哈希算法都是用来处理字符串匹配的问题。KMP算法通过利用已知信息来减少比较次数,提高匹配效率;而字符串哈希算法则是将字符串转化为哈希值,便于进行比较和存储。两者都在一定程度上提高了字符串匹配的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值