一般想到字符串的匹配算法,大家很快就會想到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;
}