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

    }

    原文作者:KMP算法
    原文地址: https://blog.csdn.net/u014422406/article/details/52685800
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞