Java ———KMP算法(字符串匹配)

问题:假设有这么一类问题:存在2个字符串,其中一个是另外一个的子串。
例如:
输入s1=abcd,s2=bc,输出:1。abcd从0开始算起。
解决一:
暴力遍历解决(遍历!!!)
思路:假设S=[a,b,c,d],p=[bc],找出P在S中的位置
1.判断s[0]==p[0],显然a!=b.
2.根据i=i-j+1,j=0; 判断s[0]==p[1],b==b成立
3.i++,j++; 判断s[1]==p[2],c=c成立,此时 符合j==p.length长度
4.return回去,已找到P字符串在S中的位置
贴代码

    public static int baoli(String s[],String p[]){
        int i=0,j=0;
        while(i<s.length&&j<p.length){
            if(s[i]==p[j]){
                i++;
                j++;
            }
            else {
                i=i-j+1;
                j=0;
            }
        }
        if(j==p.length) {
            return i - j;}
     else return -1;
    }

解法二
KMP算法
定义:Knuth-Morris-Pratt 字符串查找算法,简称为 “KMP算法”,常用于在一个文本串S内查找一个模式串P 的出现位置。
此算法可以在O(m+n)的时间数量级上完成串的模式匹配操作。其改进在于:每当一趟匹配过程中出现字符比较不等时,不需回溯i指针,而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽肯能远的一段距离后,继续进行比较。
例:
假设两个字符串 abcac , ababc abcac bab

第一趟匹配
i=3
a b a b c a b c a c b a b
a b c
j=3
第二躺匹配
i=3->i=7
a b a b c a b c a c b a b
a b c a c
j=1->j=5, 到第5个字符不匹配
第三趟匹配
i=7->i=11
a b a b c a b c a c b a b
(a)b c a c
j=1->j=6,5个字符匹配完成

通过对上述观察,我们可以看到i=4和j=1,i=5和j=1以及i=6,j=1这三次比较都是不必进行的,因为从第三趟结果就可以知道主串中4,5,6必然是bca,(即模式中的2,3,4)。因为模式中的第一个字符为a,因此它无需再和这三个字符进行比较,而仅需将主串中的i=4移到i=7,用i=7与j=2进行比较即可。
同理,在第一趟匹配出现字符不等时,继续将i向又移动两个字符的位置继续进行i=3,j=1的字符比较。
结论:失配时
模式串(针对整个模式串)向右移动的位数=已匹配字符数 - 失配字符的上一位字符所对应的最大长度值
得知最大长度表变可求next数组
所以我们要知道最大长度表怎么算。(以下例子很形象)
这里写图片描述
next 数组相当于“最大长度值” 整体向右移动一位,然后初始值赋为-1。就是找最大对称长度的前缀后缀,然后整体右移一位,初值赋为-1
然后便可用next数组来改变刚刚的公式
则失配时,
模式串向右移动的位数为=失配字符所在位置 - 失配字符对应的next 值
看了大致介绍,先贴代码根据代码讲解

public class KMPSearch {
    public static int kmpsearch(String s,String key,int[] next){
          int i=0;
          int j=0;
     while (i<s.length()&&j<key.length()){
         //如果j=-1或者当前字符串匹配陈功(即s[i]==key[j]),都令i++.j++
         if(j==-1||s.charAt(i)==key.charAt(j)){
         i++;
         j++;
         }
         else {
             //如果当前j!=-1,且当前字符匹配失败(即s[i]!=key[j]),则令i不变,j=next[j]
             //next[j]即为j对应的next值
             j=next[j];
         }
     }
     if(j==key.length()){
         return i-j;
     }
     else return 0;
    }
    public static int[] kmpnext(String key){
        int next[]= new int[key.length()];
        next[0]=-1;
        int k=-1;
        int j=0;
       while (j<key.length()-1){
           if(k==-1){
               next[++j]=0;
               k=0;
           }
           else if(key.charAt(j) == key.charAt(k)){//确定next(j+1)的值
        k++;
        next[++j]=k;
           }
           else k=next[k];
       }
        return next;
    }
    public static void main(String args[]){
        String str1="sdffsefdbababa";
        String key="ababa";
        int[] next=kmpnext(key);
        int res=kmpsearch(str1,key,next);
        System.out.println(res);
}
}

可从分析定义用递推的方法求next函数值
定义next[0]=-1;
设next[j]=k,则表明以下关系’p1……pk-1’=’pj-k+1……pj-1’
则求next[j+1]=?肯能有两种情况:
1.若pk=pj,则表明 ‘p1……pk’=’pj-k+1……pj’
next[j+1]=k+1=next[j]+1
2.若pk!=pj,则表明’p1……pk’!=’pj-k+1……pj’
则next[j+1]=k’+1
则next[j+1]=next[k]+1
所以得到next[j+1]=1.
所以总结来说next[0]=-1,比较k,j。
若S[k]=S[j],则next[j+1]=k+1.两者+1
若不相等则k[next]=k,对k重新赋值再比较,直到j循环结束。

参考:http://blog.csdn.net/christ1750/article/details/51259425
http://blog.csdn.net/v_july_v/article/details/7041827
http://blog.csdn.net/lzy969737017/article/details/38088865

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值