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));
    }
}

 

 

 

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