一般想到字符串的匹配算法,大家很快就会想到KMP,毕竟教科书上都是介绍它相关的内容,但是前面在准备面试的过程中,发现了一种效率不比它差,但是简单易懂的算法。感觉这种算法确实很有意思。
首先两个字符串
例如:在eaabb babadbbcd 中找adcbb
首先
eaabb babadbbcd :i A
adcbb :j B
对齐,然后一个一个匹配:得出在index为0,1,2的位置均相等,
eaabb babadbbcd
adcbb
但是index 位2的位置不相等,sunday算法的基本思路是
【1】找跳转指示:不匹配的时候,看较长的字符串中对齐后冒出了的第一个字符,这里就是b。
【2】根据指示字符找出能够跳的最大步数,尽可能的往后面跳,这里的这个字符是b,然后具体怎么跳:
- 如果个字符不在短的字符串中出现,说明我前面和现再所处的这个字符,在我要匹配的字符串中没有,那我就直接跳过你,在你的后面开始重新匹配。比如这里的b改成z,就直接把短的给对齐到z后面。
eaabbbabadbbcd i=7 指示a
__ _adcbb j=0指示 a 如果出现就把短字符串的最后出现b(为什么是最后出现,因为你看下面的例子,如果是前一个b对齐,那么i就跳得更远,而最后对齐这种潜在的可能匹配的情况就被忽略掉了)的位置和这个指示位置对齐。当然还是从头开始匹配,接下来看他们的前面那部分是否相等,,为什么这么对齐,因为这么对齐后可能会出现匹配,相对于一次跳一步这种方法可以尽可能的排除去不可能的情况。
efcabcbabadbbcd i=2 指示c
__adcbb j=0指示apublic static int SundayMatch(String str,String patten){ int len1=str.length(); int len2=patten.length(); int[] map=new int[256]; for(int i=0;i<256;i++){ map[i]=-1; } for(int i=0;i<len2;i++){//如果有相同的,显然就保存了最后一个字符的index map[patten.charAt(i)]=i; } for(int i=0;i<len1-len2;){ int j=0;//每次跳完后j都是0 while(j<len2){ if(str.charAt(i)==patten.charAt(j)){ i++; j++; }else{ //一遇到不匹配就往后跳 int index=i+len2-j;//跳到不匹配的第一个字符,index表示它的位置 char p=str.charAt(index); if(map[p]==-1){ //如果str中没有这个字符i直接跳 i=index+1; //不管你前面了就直接跳到后面 }else { i=index-map[p];//index-1 - (map[p]-1) 前者表示对齐后长字符串的最后一个字符,后者表示还要往前看map[p]-1个字符是否匹配 //由于map[p]表示p在短字符中的index如b的最后一个index=5的话,i就必须往前看4个字符 } break; } } if (j == len2) { return i - len2;//匹配完后停留在尾端,和头相差len2的距离 } } return -1;
}