KMP算法代码

public class kmp {

   /*
    * KMP算法匹配字符串
    * 
    *
    * 
    * 前缀:必须包括首字符不包括尾字符的所有字符串
    * 后缀:必须包括尾字符不包括首字符的所有字符串
    * 部分匹配值:寻找前缀和后缀的最大共有字符串的长度(K值)
    * 部分匹配的实质是,有时候,字符串头部和尾部会有重复。比如,"ABCDAB"之中有两个"AB",那么它的"部分匹配值"就是2("AB"的长度
    * )。搜索词移动的时候,第一个"AB"向后移动4位(字符串长度-部分匹配值),就可以来到第二个"AB"的位置。
    *    
    */

    /**
     * 求next值
     * @param strs
     * @return
    寻找字符串每一位的部分匹配值,由于前一位字符串的最大共有字符串长度(部分匹配值K)已经知道了,
    既strs[0]--strs[k-1]==strs[length-2-k]..strs[length-2]。
    所以我们的工作是比较K+1位字符和当前位置是否相等(strs[k] ?= strs[length-1]),例如:
    _______________________________
    next[]          2                  5         
    a b c a b a b a b c a b d
    |  |  |  |  |        |  |  |  |  |   
    a b c a b   = a b c a b   
    a         ?=     d
    ______________________________
    长度为length-1的字符串的部分匹配值为5(next[11]=5)
    所以当需要匹配下一位的字符串的部分匹配值时,因为前面字符串的匹配值为5,我们只需比较5+1的字符和最后一位字符,既比较第6位和最后一位是否相等。
    如果不相等,查找前一位的第二大相同字符串,由于前缀和后缀的特性,第二大相同字符串必定在两个abcab里面。所以我们只需求出abcab的最大相同字符串。
    而abcab的最大相同字符串长度我们已经算出(next[4]=2)
    所以我们现在只要比较最后一位和2+1的字符是否相等,如果不相等,重复上一步操作,直到部分匹配值为0,公式如下:
    strs[length-1] ?=strs[k] 
    if(strs[length-1]!=strs[k] )         
    k = next[k-1]
    strs[length-1] ?=strs[k]
    if(==) k++;
     */
    public int[] sortSon(char[] strs) {
        int length = strs.length;
        int[] next = new int[length];
        int k = 0; // next值
        next[0] = k;
        for (int i = 1; i < length; i++) {
            while (k != 0 && strs[i] != strs[k]) {
                k = next[k - 1];
            }
            if (strs[i] == strs[k]) {
                k++;
            }
            next[i] = k;
        }
        return next;
    }
    /**
     * 查找出匹配字符串的首字母下标,步骤和求next值差不多
     * 匹配失败时,根据所求的next值移动位置
     * @param father
     * @param son
     * @return
     */
    public int kmp( char father[],char son[])
    {
        int fatherLength,sonLength;
        fatherLength = father.length;
        sonLength = son.length;
        int[] next = sortSon(son);
        int k = 0;
        for (int i = 0; i < fatherLength; i++)
        {
            while(k> 0 && father[i] != son[k]){
                k = next[k-1];
            }
            if(i-k+sonLength>fatherLength){   //判断匹配的长度是否越界
                return -1;
            }
            if (father[i] ==son[k])
            {
                k++;
            }
            if (k == sonLength)
            {
                return i-sonLength+1;
            }
        }
        return -1;
    }

    public void test(){
        char[] father = "eeeabcdfe".toCharArray();
        char[] son = "abcdef".toCharArray();;
        char[] father2 = "abeabcdef".toCharArray();
        char[] son2 = "abcdef".toCharArray();;
//     kmp(father, son);
        Log.e("kmp", "匹配的下标为:"+kmp(father, son));
        Log.e("kmp", "匹配的下标为:"+kmp(father2, son2));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值