比KMP更簡單更有意思的Sunday算法

一般想到字符串的匹配算法,大家很快就會想到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,然後具體怎麼跳:

  1. 如果個字符不在短的字符串中出現,說明我前面和現再所處的這個字符,在我要匹配的字符串中沒有,那我就直接跳過你,在你的後面開始重新匹配。比如這裏的b改成z,就直接把短的給對齊到z後面。
    eaabbbabadbbcd i=7 指示a
    __ _adcbb j=0指示 a
  2. 如果出現就把短字符串的最後出現b(爲什麼是最後出現,因爲你看下面的例子,如果是前一個b對齊,那麼i就跳得更遠,而最後對齊這種潛在的可能匹配的情況就被忽略掉了)的位置和這個指示位置對齊。當然還是從頭開始匹配,接下來看他們的前面那部分是否相等,,爲什麼這麼對齊,因爲這麼對齊後可能會出現匹配,相對於一次跳一步這種方法可以儘可能的排除去不可能的情況。
    efcabcbabadbbcd i=2 指示c
    __adcbb j=0指示a

    public 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;
    

    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章