KMP算法实现的个人理解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/madonghyu/article/details/80494613

使用python3进行实现


关于KMP算法,其时间复杂为F(n+m),即只需遍历一次字符串就能找出第一个匹配的字符,实现的核心就是求解next数组,


而next数组,实际上就是一个存放着当匹配到这一位失去匹配时,模式串的平移位数。
例如模式串abcabca,当在最后一位匹配失败的时候,如果是使用一般做法的话,就是将遍历两个字符串的下标重置,当是实际上只需要将模式串平移三位,用第四位的a继续进行匹配就行了。
关于next数组的求解理解起来感觉有点困难,首先要理解最长前缀的概念,这也是求解这个数组的最主要原理


下面是最长前缀的几个例子
abca的最长前缀是aab没有最长前缀,abcabc的最长前缀是abc


之后就是理解最长前缀的用处了,以abcabcabca为例子,如果在前四位匹配出错,那么都是直接往下继续匹配就行了,模式串不需要平移,只有当第五位的b出现失配,模式串才需要平移一位(这里其实还有优化方案,因为b和第二位的b一样,实际上不需要匹配,这个可以优化,这里就暂时不做讨论)
平移一位之后就是用第二位的b进行匹配,同理可知第六位失去匹配的情况,字符串要平移两位,而这个平移位数就是由最长前缀决定的,在第五位b前面的字符,最长前缀为a,长度为一
因此平移一位


那么求解数组就简化成一个问题,那就是求解一个字符串每一位前面的字符串的最长前缀,而第一位则为-1,如果为-1则表示模式串的第一位与被匹配字符串当前位置的字符不匹配


next数组求解的代码:

        def next(target):
    #模式串最长前缀串的下标    
            j = -1 
    #next数组,规定第一位为-1,当匹配时为-1时则表示第一位与当前被匹配字符串的当前字符不匹配
            next = [-1] 

    #初始化next数组
            i = 1 #从第二位开始
            while i < len(target):
                next.append(0)
                i+=1

            i = 0
            while i < len(target) - 1:#next数组求解是按下一位赋值的,因此为要减一
                if j==-1 or target[i] == target[j]:
                    i+=1
                    j+=1
                    next[i] = j
                else:
                    j = next[j]#当失去匹配时回溯到前一位的最长前缀的下标
            return next

求解的代码的实现十分的简单,这个算法实现了只遍历一遍字符串就求得next数组,实际上如果你不理解也可以采用两个for循环进行求解。。。
主要难以理解的地方还是j = next[j]这一句,这一句主要是为了得到之前的最长前缀,这样如果这个位置的字符匹配的话就可以直接加一


回到之前那个优化的问题,abcabcabca,当第五位的b出现失配,模式串平移一位,当实际上并不需要比较b,而是应当重置为第一位,因为就算是从第二位比较,也会因为不匹配而退回第一位,这样子的话就会导致多匹配一次,这个时候可以这样修改一下匹配的代码

                if j==-1 or target[i] == target[j]:
                    i+=1
                    j+=1
                    if  target[i] == target[j] :
                        next[i] = next[j]
                    else:
                        next[i] = j
                else:
                    j = next[j]

如果匹配的话就回溯到匹配成功的字符下标对应的最长前缀


进行匹配的代码:

#返回的是第一次匹配的下标,0位第一位
    def strStr(source, target):
    #排除字符空的情况
        if target is None or source is None:
            return -1
    #得到next数组
        list = next(target)
        i = 0
        j = 0
        l1 = len(source)
        l2 = len(target)
        while i < l1 and j < l2:
        #当为-1的时候说明当前位与第一位并不匹配,可以直接跳过
            if j==-1 or source[i] == target[j]:
                i+=1
                j+=1
            else:
                j = list[j]
        if j == l2:
            return i-j
        else:
            return -1

猜你喜欢

转载自blog.csdn.net/madonghyu/article/details/80494613