串 - KMP算法

数据结构算法中重中之重。肯定考。Needless to say, 除了蛮力算法之外, 据说还有 30+ 种知名算法。

网上搜了点资料,比较冗长。

 

1.自己使用过的资料

王道计算机考研 数据结构 -- 原因:讲课比较容易听得进去

https://www.bilibili.com/video/BV1b7411N798?p=40&spm_id_from=pageDriver&vd_source=63764dd9776224d187bddddb05bf9f3f

 

学堂在线 邓俊辉 数据结构(下)  -- 比王道更甚

https://www.xuetangx.com/learn/THU08091002048/THU08091002048/14768880/video/30260006

 

 

2.未使用的资料

KMP算法详解 字节跳动工程师写的,这次先不看了

https://zhuanlan.zhihu.com/p/83334559

 

KMP算法详解-彻底清楚了(转载+部分原创)

https://www.cnblogs.com/dusf/p/kmp.html

 

很详尽KMP算法(厉害)

https://www.cnblogs.com/zzuuoo666/p/9028287.html

 

 

 王道考研 主算法

 

学堂在线 主算法

 

buildNext()

 

buildNext() 改进版本

 

 

针对该算法,ShoelessCai 打算用几个问题来梳理清楚:

 

1. 算法返回什么? 返回的是 主串的位置。从代码上看是 i - j 其实就是主串绝对位置。

 

2. 算法输入什么? 主串、模式串(较短的)、Next数组(记录模式串位置,记住,Next[] 长度与模式串一致,并且可由 模式串直接计算得出)

 

3. 基本思想:

(1)如果匹配失败的时候,失败的位置记录为 j,那么,我从 j+1 再开始和模式串匹配。

(2)如果模式串(较短的)内部也有较多重复,例如 ababaaa。在某些位置,还可以往后面多跳一格

 

4. Next[] 长度和模式串(较短的)一致。

(A) 构造方法-I(王道):

匹配 SLOT 之前最长子串,比较前缀、后缀重叠的 SLOTS 个数,姑且称为 N。Next[] 中的元素为 N+1

(B) 构造方法-II(学堂): 

如果 匹配成功,则两个指针 i, j 均后移

如果 匹配不成功,但是 t<0 (从第一个字符开始匹配的情况),则 Next[j] = t 。直接将 t 返回给 Next[]

算法效果:失配后回到上一个一样的字符的前一个位置,再失败,回到上上个一样字符的前一个位置。见下文 next_generate_1()

 

关于 NEXT[]

发现用语言表述还是显得信息量太过少了。那就贴代码。

 Python 版本  -- 考试的时候也是看思路,这一点我倒不怀疑。

 

'''--------------------------
    408/912 关于串
    KMP算法
----------------------------'''
import numpy as np
import pandas as pd

 

函数准备:1. Next构造 2. Next 构造改进 3.主函数

# --- 两个函数, next_generate() && kmp_compare()

def next_generate(str_in):
    m=len(str_in); j=0; cnt=0
    N=[]; N.append(-1); t=-1; # -- t 为指针 
    
    while(j<m-1 and cnt < 1000):
        if( t<0 or (str_in[j] == str_in[t]) ):
            j=j+1; t=t+1
            N.append(t)
        else:
            t=N[t]      
        cnt=cnt+1
        
    return N


  # --- 改进:失配后,回到上个匹配过的位置,上个匹配的也失败,则回到上上个
  # --- 注意是i-1 position

def next_generate_1(str_in):
    m=len(str_in); j=0; cnt=0
    N=[]; N.append(-1); t=-1; # -- t 为指针 
    
    while(j<m-1 and cnt < 1000):
        if( t<0 or (str_in[j] == str_in[t]) ):
            j=j+1; t=t+1
            if ( str_in[j] != str_in[t] ):
                tmp_out=t
            else:
                tmp_out=N[t]
            N.append(tmp_out)
        else:
            t=N[t]
        cnt=cnt+1
        
    return N


  # --- 主程序
def kmp_compare(str_short, str_long, next_mode=1):
    
      # -- generate NEXT[]
    if ( next_mode==1 ):
        next_ind = next_generate(str_short)
    elif ( next_mode==2 ) :
        next_ind = next_generate_1(str_short)
    else:
        print("Next Generation Wrong! \n")
        return -1
    print("Next: ", next_ind)
    
      # -- 双指针
    n=len(str_long); i=0;
    m=len(str_short); j=0; cnt=0
    
    while( j<m and i<n ):
        if( j<0 or str_long[i]==str_short[j] ):
            i=i+1
            j=j+1
        else:
            j = next_ind[j]
        cnt=cnt+1
            
    del next_ind
    print("Calculation Round: ", cnt, "\n")
    return i-j

 

调用函数的部分

str_l="duovwababaaaacdfbivf"
str_s="ababaaaa"


  # --- 调整 next_mode =1/2 设置不同的 Next[] 构造
tmp = kmp_compare(str_s, str_l, next_mode=2)

print("The long string: ", str_l, "\n And the short string: ", str_s, "\n")
print("The outcome position: ", tmp)

 

执行结果

 

欢迎关注 ShoelessCai.com 。

 

posted on 2023-11-03 12:06  Mira_2019  阅读(20)  评论(0编辑  收藏  举报