KMP模式匹配算法

本文深入讲解KMP算法,探讨如何高效地在主串中查找子串,避免重复遍历。介绍Next函数及其改进Nextval函数的实现原理与代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

KMP算法主要解决的问题是如何较为高效地在主串中寻找指定的字串。这种算法可以大大避免朴素匹配中出现的重复遍历的情况。算法的实质是利用字子串自身所具有的一些特殊性质,得到一个函数返回函数Next,从而通过函数Next来避免大量重复遍历的情况。
下面先给出函数Next的定义:
对于字符串T(也可看成是字符列表)
Next[j]={−1j=0max{k∣0&lt;k&lt;j and T[0:k]=T[j−k:j]}当此集合不为空时0其他情况 Next[j]=\begin{cases} -1 &amp; j=0 \\ max\{k|0&lt;k&lt; j\ and\ T[0:k]=T[j-k:j]\} &amp;当此集合不为空时 \\ 0&amp;其他情况\\ \end{cases}Next[j]=1max{k0<k<j and T[0:k]=T[jk:j]}0j=0
定义的意义:设主串为SSS,子串为TTT,假设比较进行到了S[i],T[j]S[i],T[j]S[i],T[j]处,且S[i]!=T[j]S[i]!=T[j]S[i]!=T[j]
 1.当j=0j=0j=0时,Next[j]=−1Next[j]=-1Next[j]=1,此时需要进行的比较为S[i+1]S[i+1]S[i+1]T[j+1]T[j+1]T[j+1]
 2.当{k∣0&lt;k&lt;j and T[0:k]=T[j−k:j]}\{k|0&lt;k&lt; j\ and\ T[0:k]=T[j-k:j]\}{k0<k<j and T[0:k]=T[jk:j]}不为空时,
按照NextNextNext定义取Next[j]=max{k∣0&lt;k&lt;j and T[0:k]=T[j−k:j]}Next[j]=max\{k|0&lt;k&lt; j\ and\ T[0:k]=T[j-k:j]\}Next[j]=max{k0<k<j and T[0:k]=T[jk:j]},因为对于T[0:j]T[0:j]T[0:j]已经同S[i−j:i]S[i-j:i]S[ij:i]比较过且相等,又因为T[0:k]=T[j−k:j]T[0:k]=T[j-k:j]T[0:k]=T[jk:j],这意味着已经得到S[i−k:i]=T[0:k]S[i-k:i]=T[0:k]S[ik:i]=T[0:k],故需要比较的只有T[k:]T[k:]T[k:]S[i:]S[i:]S[i:],故此时NextNextNext的意义是避免了对T[0:k]T[0:k]T[0:k]做无谓的比较,让子串与主串的比较直接从子串的第k处开始。
 3.当为其他情况时,直接从头开始比较。

Next代码

def get_Next(T):
    
    j=0
    Next=[-1]
    for j in range(1,len(T)):
        
        K=[k for k in range(2,j+1) if T[0:k-1]==T[j-k+1:j] and k-1>0]
        if K:Next.append(max(K)-1)
        else:Next.append(0)

    return Next

完整代码

# -*- coding: utf-8 -*-
"""
Created on Fri Mar 15 10:14:32 2019

@author: Administrator
"""

def get_Next(T):
    j=0
    Next=[-1]
    for j in range(1,len(T)):
        K=[k for k in range(1,j) if T[0:k]==T[j-k:j] and k>0]
        if K:Next.append(max(K))
        else:Next.append(0)

    return Next

def Index_KMP(S,T,pos=0): 				#S:主串,T:子串,pos:在主串中开始搜寻的位置
    j=0
    i=pos
    Next=get_Next(T)
    while (i<len(S) and j<len(T)):

        if j==-1 or S[i]==T[j]:
        #即在上一次比较中发现子串T中第一个字母便与S[i]不同,或者是S[i]==t[j],则主串和子串的指标i,j均往后移1个位置
            i+=1
            j+=1
        else:
        #即j!=-1且S[i]!=T[j]
            j=Next[j]
    if j==len(T):
    #如果对于T比较完成,则返回主串中对应位置的开头
        return i-len(T)
    else:
        return -1
    
S='dasdfhaskaslsfkjhfweiu'
T='askasls'
Index_KMP(S,T,pos=0)

关于Next函数的改进NextvalNextvalNextval

改进的实质:在S[i]!=T[j]时,在计算NextNextNext的值的同时,如果jjj位字符与它NextNextNext值所指向的Next[j]Next[j]Next[j]位字符相等,则该jjj位的NextvalNextvalNextval就指向Next[j]Next[j]Next[j]位的NextvalNextvalNextval值,这是因为jjj位字符如果通过NextNextNext回到前面的字符位置后,接下来要进行比较的就是T[Next[j]]T[Next[j]]T[Next[j]]S[i]S[i]S[i],而我们已经比较得到S[i]!=T[j]S[i]!=T[j]S[i]!=T[j],故若T[j]=T[Next[j]]T[j]=T[Next[j]]T[j]=T[Next[j]],则也有T[Next[j]]!=S[i]T[Next[j]]!=S[i]T[Next[j]]=S[i],故需要再次通过NextNextNext返回,即返回至Next[Next[j]]Next[Next[j]]Next[Next[j]];如果不相等,则jjj位的NextvalNextvalNextval值就是它自己iii位的NextNextNext值。

Nextval代码

def get_Nextval(T):
    j=0
    Nextval=[-1]
    for j in range(1,len(T)):
        K=[k for k in range(1,j) if T[0:k]==T[j-k:j] and k>0]
        if K:
            if T[max(K)]==T[j]:Nextval.append(Nextval[max(K)])
            else:Nextval.append(max(K))
        else:
            if T[j]==T[0]:Nextval.append(-1)
            else:Nextval.append(0)
            
    return Nextval
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值