Kmp优化算法

Posted 优化大师傅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kmp优化算法相关的知识,希望对你有一定的参考价值。

typedef struct
    
    char data[MaxSize];
    int length;            //串长
SqString;
//SqString 是串的数据结构
//typedef重命名结构体变量,可以用SqString t定义一个结构体。
void GetNext(SqString t,int next[])        //由模式串t求出next值

    int j,k;
    j=0;k=-1;
    next[0]=-1;//第一个字符前无字符串,给值-1
    while (j<t.length-1) 
    //因为next数组中j最大为t.length-1,而每一步next数组赋值都是在j++之后
    //所以最后一次经过while循环时j为t.length-2
        
        if (k==-1 || t.data[j]==t.data[k])     //k为-1或比较的字符相等时
            
            j++;k++;
            next[j]=k;
            //对应字符匹配情况下,s与t指向同步后移
            //通过字符串"aaaaab"求next数组过程想一下这一步的意义
            //printf("(1) j=%d,k=%d,next[%d]=%d\\n",j,k,j,k);
           
           else
        
            k=next[k];
            **//我们现在知道next[k]的值代表的是下标为k的字符前面的字符串最长相等前后缀的长度
            //也表示该处字符不匹配时应该回溯到的字符的下标
            //这个值给k后又进行while循环判断,此时t.data[k]即指最长相等前缀后一个字符**
            //为什么要回退此处进行比较,我们往下接着看。其实原理和上面介绍的KMP原理差不多
            //printf("(2) k=%d\\n",k);
        
    

 

KMP字符串匹配算法的优化

  KMP算法是什么,我在这里就不做过多赘述了。

  KMP算法的nextval数组中,会有一些重复项。例如:"aaaab"对应的nextval数组是[-1, -1, -1, -1, 3],"114514"对应的nextval数组是[-1, -1, 1, 0, -1, 1]。很明显,字符串中的字符和nextval数组中的数值是映射关系,我们把这个映射叫做nextval映射。

  也就是"aaaab"和"114514"的nextval映射是:‘a’:-1, ‘b’:3和‘1’:-1, ‘4’:1, ‘5’:0。

  其实数组也算是一种映射。我们这里无非就是把数组索引值与数组元素的映射替换成了字符与数组元素之间的映射。

  上代码:

import java.util.HashMap;
import java.util.Map;

public class MyString implements CharSequence 

	public int indexOf(CharSequence that) 

		Map<Character, Integer> nextVal = new HashMap<>();

		int i = -1;
		int j = -2;
		
		/* 获得nextval映射 */
		while (i < that.length() - 1) 
			if (j < 0 || that.charAt(i) == that.charAt(j)) 
				nextVal.putIfAbsent(that.charAt(++i), ++j);
			 else 
				j = nextVal.get(that.charAt(j));
			
		

		// System.out.println(nextVal);

		i = 0;
		j = 0;

		/* 双指针匹配 */
		while (i < this.length() && j < that.length()) 
			if (j < 0 || this.charAt(i) == that.charAt(j)) 
				i++;
				j++;
			 else 
				j = nextVal.get(that.charAt(j));
			
		

		return j > that.length() - 1 ? i - that.length() : -1;

	


  哈希表的插入和查找复杂度都是O(1)。所以这个算法时间复杂度空间复杂度和原来的KMP算法一样。有人可能就说了,你这放着数组不用用散列,重新写个数据结构,开销老大了,这算法写的有够烂的。

  确实,如果说在"1145141919810"中匹配"1919810",我这个算法无论是时间还是空间上都干不过原版的算法。尤其是不带重复的,例如"abcdefgh"中匹配"def",那就更拉胯了。

  但我们想想另一种情况,你有天在网上看到一大段莎翁节选,但是上面没有写出自哪一篇的哪一段。你想知道的话,就得把一大段文字放到上MB的字符串里去匹配。这种情况下,用映射关系的优势就显而易见的出来了。一长段文字放到数组里就是一个庞大的nextval数组,但是放到映射里,算上英文的二十六个字母,甚至空格、标点符号,他的容量也绝对不会超过100个键值对。

  也就是说这个算法的字符串匹配适合于大规模的匹配。

以上是关于Kmp优化算法的主要内容,如果未能解决你的问题,请参考以下文章

KMP算法

C++ 算法进阶系列之从 Brute Force 到 KMP 字符串匹配算法的优化之路

数据结构串---KMP模式匹配算法实现及优化

KMP算法的正确性证明及一个小优化

KMP算法

KMP算法