KMP算法(四):Sunday算法 Java實現

一、Sunday算法思想

備註:因爲Sunday理解起來比較簡單,就直接用參考的文章內容了。鏈接:https://www.cnblogs.com/sunsky303/p/11693792.html

Sunday算法是從前往後匹配,在匹配失敗時關注的是主串中參加匹配的最末位字符的下一位字符。

如果該字符沒有在模式串中出現則直接跳過,即移動位數 = 模式串長度 + 1;

否則,其移動位數 = 模式串長度 - 該字符最右出現的位置(以0開始) = 模式串中該字符最右出現的位置到尾部的距離 + 1。

 

二、需要注意的問題

 

1、如果父串中對應子串末尾下一個位置的字符在子串中存在,且不止一個要怎麼處理

方法:爲了不遺漏可能的匹配,應該是跳到使得子串中最右一個字符與父串中的該字符對應,這樣跳過的距離最小,且是安全的。

 

2、可能會出現最後一次移動後father剩餘長度與son長度不一致的情況

方法:做循環時,while條件判斷中加上子串移動的位置,如下代碼

while (i <= fatherLength - sonLength + j)

三、Java代碼實現

 

public class Sunday {

    /**
     * 判斷子串中是否存在末尾下一個位置對應的父串的字符
     * 每次從後往前匹配,爲了不遺漏可能的匹配,應該是跳到使得子串中最右一個字符與父串中的該字符對應,
     * 這樣跳過的距離最小,且是安全的。
     */
    public static int contains(char[] sonArray, char ch) {
        for (int i = sonArray.length - 1; i >= 0; i--) {
            if (sonArray[i] == ch) {
                return i;
            }
        }
        return -1;
    }

    public static int search(String father, String son) {
        //這裏轉爲char數組要更方便些
        char[] fatherArray = father.toCharArray();
        char[] sonArray = son.toCharArray();

        int fatherLength = fatherArray.length;
        int sonLength = sonArray.length;
        int i = 0, j = 0;
        //+ j是可能會出現最後一次移動father剩餘長度與son長度不一致的情況
        while (i <= fatherLength - sonLength + j) {
            if (fatherArray[i] != sonArray[j]) {
                //如果父串與子串當前字符不相等
                if (i == fatherLength - sonLength + j) {
                    //這裏說明子串已經是在和父串中最後可能想等的字符比較過了,並且後面也沒有可比較的了,所以返回
                    return -1;
                }

                //如果父串的中間部分與子串匹配,且結果不相等
                //就從子串最後面開始,找出子串最後一位的下一位對應父串的字符在子串中是否存在
                int pos = contains(sonArray, fatherArray[i - j + sonLength]);
                if (pos == -1) {
                    //不存在則直接跳到再下一位,子串從頭開始
                    i = i - j + sonLength + 1;
                    j = 0;
                } else {
                    //存在則將這個字符與子串最右邊與它相同的字符對其,並再次從頭開始比較
                    i = i + sonLength - pos - j;
                    j = 0;
                }

            } else {
                //如果父串與子串當前字符相等
                if (j == sonLength - 1) {
                    //如果比較到了子串的最後一位,說明已經存在
                    return i - j;
                } else {
                    //不是子串最後一位,則進行下一個字符的對比
                    i++;
                    j++;
                }

            }


        }

        return -1;
    }

    public static void main(String[] args) {
        String father = "ABABEABABABABCBA";
        String son = "ABABC";
        System.out.println(search(father, son));
    }
}

 

 

 

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