KMP算法

来源:互联网 发布:数控车大螺距螺纹编程 编辑:程序博客网 时间:2024/06/06 14:16

2015-5-31
今天在leetcode上遇到一个问题,shortest palindrome
由此想到了字符串查找的高效一点的算法

先介绍kmp算法:

使用kmp算法可以将字符串搜索的时间复杂度降到 O(m+n),m和n分别是original和find字符串的长度。(当然还有改进的空间=。=
这个算法的主要思想是,当匹配失败的失败的适合,不是从下一个字符开始尝试匹配,而是充分利用已经匹配的信息,一次跳多个字符去匹配
具体做法是,先对find字符串求next数组,next[i]的含义是,从find字符串中前缀和后缀相同的最大长度,例如:ababab,next[3]表示的是子字符串aba的前缀和后缀相同的最大长度,即1。以下是java实现

public int[] getNext(String b){    int len=b.length();    int j=0;    int next[]=new int[len+1];//next表示长度为i的字符串前缀和后缀的最长公共部分,从1开始    next[0]=next[1]=0;    for(int i=1;i<len;i++)//i表示字符串的下标,从0开始    {//j在每次循环开始都表示next[i]的值,同时也表示需要比较的下一个位置        while(j>0&&b.charAt(i)!=b.charAt(j))j=next[j];        if(b.charAt(i)==b.charAt(j))j++;        next[i+1]=j;    }    return next;}

根据这个next数组,在original中查找find
假设j为当前累计匹配成功的子字符串长度,方法是每次遇到匹配失败的,就找next[j],看next[j]处是否匹配成功,若匹配成功则继续向下匹配,若失败,则再找next[next[j]]如此下去直到到0。以下是java实现

public void search(String original, String find, int next[]) {    int j = 0;    for (int i = 0; i < original.length(); i++) {        while (j > 0 && original.charAt(i) != find.charAt(j))            j = next[j];        if (original.charAt(i) == find.charAt(j))            j++;        if (j == find.length()) {            System.out.println("find at position " + (i - j));            System.out.println(original.subSequence(i - j + 1, i + 1));            j = next[j];        }    }}

回到原题

我的思路是找到字符串中以第一个字母为起点的最长回文子字符串,找到之后,就只要把剩下的字符串倒叙放在原来的字符串前面,以示例输入(‘aacecaaa’)为例,它的最长回文子字符串是aacecaa,最后在前面加个a便可。
具体步骤 :
1. 使用getnext函数得到string的next数组。
2. 接下来就是找从string末尾开始向前的子字符串中,能匹配的string前缀的最大长度,终止条件为两个字符串第一次“遇到”,此时便找到了以string首字母为首的最大回文子字符串。例如“aacecaaa”,就从最后一个a开始向前,找匹配“aacecaaa”本身的字符串,search中的终结条件改为,当从前到后匹配的位置和从后向前匹配的位置有交叉时停止。

幸运的是,实现这个功能只要把search函数稍微改一下即可,下面是具体的java代码

    public String search(String original, int next[]) {        int j = 0;        char[] result=null;        int length=original.length();        for (int i = original.length()-1; i >= 0; i--) {            while (j > 0 && original.charAt(i) != original.charAt(j))                j = next[j];            if (original.charAt(i) == original.charAt(j))                j++;            if (j==i) {                result=new char[(length-j)*2];                int r_len=result.length;                for(int t=0;t<length-j;t++){                    result[t]=original.charAt(length-1-t);                    result[r_len-1-t]=result[t];                }            }else if(j==i+1){                result=new char[2*length-j*2+1];                int r_len=result.length;                for(int t=0;t<length-j;t++){                    result[t]=original.charAt(length-1-t);                    result[r_len-1-t]=result[t];                }                result[length-j]=original.charAt(j-1);            }        }        return new String(result);    }
0 0
原创粉丝点击