定义:
串是由零个或多个字符组成的有限序列,又叫字符串。
相关概念:
零个字符的串称为空串。
只包含空格的串称为空格串,注意它与空串的区别。
串中任意个数的连续字符组成的子序列称为该串的子串。包含子串的称为主串。子串在主串中的位置就是子串的第一个字符在主串中的序号。长度为n的串含有n*(n+1)/2+1(注意包含空串)。
串的模式匹配:
定义:
子串的定位操作。
朴素模式匹配:
public int match(String target,String pattern){
int i=0,j=0;
while(i<target.length()&&j<pattern.length()){
if(target.charAt(i)==pattern.charAt(j)){
i++;
j++;
}
else{
i=i-j+1;
j=0;
}
}
if(j==pattern.length()){
return i-j;
}
else{
return -1;
}
}
KMP模式匹配:
关键:
假设S=“abcabcabc”,T=“abcabx”。如果T串中首字符“a”与第二位字符”b”不相等,而T串中第二位字符“b”与S串中第二位字符“b”已经判断是相等的,那么也就意味着,T串中首字符“a”与S串中的第二位“b”是不需要判断也知道它们是不可能相等了。
在朴素的模式匹配算法中,S串的i值是不断的回溯来完成的,而这种回溯其实是可以不需要的,KMP模式匹配算法就是为了让这没必要的回溯不发生。既然i值不回溯,那么要考虑的变化就是j值了。j值的变化与S串没有关系,它取决于T串的结构中是否有重复的问题。
我们把T串各个位置的j值的变化定义为一个数组next,那么next的长度就是T串的长度。next数组的定义如下所示:
当j=1时,next[j]=0
当集合{k|1<k<j,'p1...k-1'='pj-k+1...j-1'}不为空时,next[j]=Max{k}
其他情况下next[j]=1
注意:该定义是建立在假设next是从1开始计数的,但是通常情况下next是从0开始计数的,因此常在应用时将该定义转化为:
当j=0时,next[j]=-1
当集合{k|0<k<j,'p0...k-1'='pj-k...j-1'}不为空时,next[j]=Max{k}
其他情况下next[j]=0
代码实现:
//求取next数组
public int[] getNext(String T){
int[] next=new int[T.length()];
next[0]=-1;
int i=0,j=-1;
while(i<T.length()-1){
if(j==-1||T.charAt(i)==T.charAt(j)){
i++;
j++;
next[i]=j;
}
else{
j=next[j];
}
}
return next;
}
//KMP匹配
public int KMP(String S,Stirng T){
int[] next=getNext(T);
int i=0,j=0;
while(i<S.length()&&j<T.length()){
if(j==-1||S.charAt(i)==T.charAt(j)){
i++;
j++;
}
else{
j=next[j];
}
}
if(j==T.length()){
return i-j;
}
else{
return -1;
}
}
KMP算法的改进:
在计算出next值的同时,如果a位字符与它next值指向的b位字符相等,则该a位的next就指向b位的next值,如果不等,则a位的next值不变。
代码实现:
public int[] getNext(String T){
int[] next=new int[T.length()];
next[0]=-1;
int i=0,j=-1;
while(i<T.length()-1){
if(j==-1||T.charAt(i)==T.charAt(j)){
i++;
j++;
if(T.charAt(i)!=T.charAt(j)){
next[i]=j;
}
else{
next[i]=next[j];
}
}
else{
j=next[j];
}
}
}