子字符串查找
子字符串查找的常见方法:暴力破解、sunday和KMP。
1、暴力查找
暴力查找就是用两个指针i,j分别指向字符串和子字符串,如果指针指向的字符相等则两指针右移;否则,指向字符串的指针i回到本次匹配的下一个位置,而指向匹配字符串的指针j回到匹配字符串的开头。
public int search(String text,String pattern){
if(text==null||pattern.length==null||text.length()<pattern.length()) return -1;
int i,M = text.length();
int j,N = pattern.length();
for(i = 0,j = 0;i<M&&j<N;i++){
if(text.charAt(i)==pattern.charAt(j)) j++;//如果指针指向字符相等
else{ //不等,则一个返回到此次匹配开始的下一个字符的位置,一个则返回到匹配字符串的起始位置
i -= j;
j = 0;
}
}
if(j==N) return i-N; //找到匹配
else return -1; //为找到匹配
}
2、sunday
暴力破解的缺点在于并没有利用已经匹配过的字符,造成重复比较。
sunday算法的思想是当匹配串(子串)和字符串(母串)指针分别指向的字符不相等的时候,比较母串与子串最右端对齐的右一位字符与子串从右向左比较,如果找到与此字符相等的字符,则以此字符的位置对齐,从头开始匹配;如果没有,则直接跳过,即移动步长是子串长度+1。重复以上操作直到找到。
比如:
字符串:abcdefghij
子串:ghi
两个指针i=0,j=0分别指向a,g,经比较发现不同,则判断子串最右端后一位在母串中的字符(d)有没有出现在字串中,经比较发现没有,则移动步数为i+=3+1(指针分别指向e,g):
abcdefghij
ghi
移动后,重新开始比较发现e,g不一样,则找到子串最右端后一位在母串中的元素h,与子串从最右端比较,找到h,则将子串和母串以h的位置对齐如下:
abcdefghij
ghi
从经比较发现子串和母串此时匹配。代码如下:
public int sundaySearch(String text,String pattern){
if(text==null||pattern==null||text.length()<pattern.length()) return -1;
int i=0,M = text.length();
int j=0,N = pattern.length();
int loc = 0;
while(i<M&&j<N){
if(text.charAt(i)==pattern.charAt(j)){ //如果字符相等
i++;
j++;
}else{
int aimS = i+N;
if(aimS>M) return -1;
char aimChar = text.charAt(aimS); //找到子串最右端的后一位在母串中的字符
int pIndex = N-1;
while(pIndex>0){
if(pattern.charAt(pIndex)==aimChar){
break;
}
pIndex--;
}
i = i+N-pIndex; //确定母串中的移动步数
loc = i;
j = 0; //子串回到起始位置
}
}
if(j==N) return loc;
return -1;
}