KMP算法的一点python笔记

注:本代码仅供理解KMP流程以及测试两者的效率比对使用,并无实用价值,虽然尽量做过测试了不过不保证完全正确,请读者自行分辨,本篇仅供吐槽与记录。

本来想写一些kmp的原理的记录不过在学习的过程中,在网上搜索到很多的文章各种图示图例都讲解的很详细了。所以,有浏览到的小伙伴直接去看这篇文章就好,开头就整理的很详细了,对着那几个超链接下来应该是会清楚了。

注:那里面那个三哥视频讲的很不错,感觉可以。

字符串的KMP算法–Python实现
主要是代码的混乱实在是让人走了很多弯路。
在此记录下这次的笔记顺便整理下各种代码,防止后面忘记了:

首先是对比的代码,BF暴力匹配:

import random
import time

random_str=''
base_str='abcdefghigklmnopqrstuvwxyz'
list_str=[]
i=0
'''
#超长串测试使用
#生成字符串
len_random=len(base_str)-1
 while i<10000:
     random_str += base_str[random.randint(0,len_random)]
     i+=1
 i=0
'''
#测试字符串
random_str='adfabfjabcxhadalkjlabfjaecjadfjaaaaaaaaaaaababfjabgxweoiulkjkabfjabcxhgoiuer'
#目标字符串
teststr='abfjabc'
len_test=len(teststr)
strnum=len(random_str)

#记录开始时间
starttime=time.time()

while i<strnum:
    #判断首字符是否相等
    if random_str[i] == teststr[0]:
        j=0
        while j<len_test:
            #内部滚动比对
            if random_str[i+j] != teststr[j]:
                #不通过就直接继续下个大循环对比
                break
            elif j==len_test-1:
                    # 全部对比通过,记录位置
                    list_str.append(i)
                    #由于相等直接跳过这个已经找到的字段
                    i += len_test-1
                    break
            j += 1
    elif strnum-i<len_test:
        #剩余长度小于字符串长度就不用进行搜索的
        break
    i+=1

#结束时间
endtime=time.time()

print('在'+str(strnum)+'长度文本中运行状况:')
print('程序的所需要的时间:'+str(endtime-starttime))
if list_str:
    print('所寻找的字符串的位置:'+','.join(str(n) for n in list_str))
    print('文中字符串的总数量'+str(len(list_str)))
else:
    print('文本内未找到所寻找的字符串')

接下来是网上的各种python获取前缀数组的代码:

import time
import random

#我自己写的代码,基本符合那个三哥视频中的示例,也是奇葩了,网上找代码什么的还是要多测下
def get_next(st):
    result_list=[]
    for i in range(1,len(st)+1):
        little_str=st[:i]
        k=0
        j=1
        len_litter=len(little_str)
        while j<len_litter:
            if little_str[:j]==little_str[-j:]:
                k=len(little_str[:j])
            j+=1
        result_list.append(k)
    return result_list

def get_next2(str):
    prefix = set()
    res = [0]
    for i in range(1, len(str)):
        prefix.add(str[:i])
        postfix = {str[j:i+1] for j in range(1, i+1)}
        res.append(len((prefix & postfix or {''}).pop()))
    return res


def get_next3(pattern):
    next = []
    pattern_list = list(pattern)
    j = 0
    i = 1
    for s in range(len(pattern)):  # 第一位一直是0
        if s == 0:
            next.append(0)  # 看第i个和第j个字母是否相同,如果相同,则累加
        # 同时i,j同时右移

        elif (pattern_list[i] == pattern_list[j]):
            next.append(j + 1)
            j += 1
            i += 1
        # 如果不相同,则next为0,同时j也退回第一个位置,i继续前进一个位置
        else:
            next.append(0)
            j = 0
            i = s + 1
    return next

'''
#生成字符串
#超长串测试使用
base_str='abcdefghigklmnopqrstuvwxyz'
random_str=''
len_random=len(base_str)-1
strnum=1000
# for i in range(1, strnum):
#     random_str += base_str[random.randint(0,len_random)]
'''

#目标字符串
#random_str='abcdabca'
#random_str='aabaabaaa'
#random_str='abcdabd'
#random_str='abfjabc'
#random_str='aaaaaaaaaaaaaaaaaaaaaaab'
random_str='abcaby'
#记录开始时间
starttime=time.time()
print(get_next(random_str))
#结束时间
endtime=time.time()
print('程序get_next所需要的时间:'+str(endtime-starttime))

#记录开始时间
starttime=time.time()
print(get_next2(random_str))
#结束时间
endtime=time.time()
print('程序get_next2所需要的时间:'+str(endtime-starttime))

#记录开始时间
starttime=time.time()
print(get_next3(random_str))
#结束时间
endtime=time.time()
print('程序get_next3所需要的时间:'+str(endtime-starttime))

最后的kmp算法

def kmp(nativestr,targetstr):
    #储存字符串中的数组位置的结果数组
    list_num=[]
    #储存next数组
    list_next=get_next(targetstr)
    j,i=0,0
    len_tar=len(targetstr)

    while i<len(nativestr):
        #开始滚动搜索,j不为0说明目标串已经匹配部分并且跳跃但是还有一部分要比对完成
        if nativestr[i]==targetstr[j] or j!=0:
            while j<len_tar:
                if j==len_tar-1 and nativestr[i+j]==targetstr[j]:
                    #字符串完整的查找出来了则开始继续寻找下一个字符串,并储存在结果数组中,并重置j
                    list_num.append(i)
                    #这里本来是要j+1 但是最后面i统一要+1循环 因此没有+1
                    i += j
                    j=0
                    break
                elif nativestr[i+j] != targetstr[j]:
                    #开始运算j对应数位的最大前缀,并进行i的下一轮移动
                    i += j-1
                    j=list_next[j-1]
                    break
                j+=1
        # elif len(nativestr)-i<len_tar:
        # #剩余的长度不够目标字符串长度的时候,退出
        #     break
        i+=1

    #空数组直接赋值-1,或根据情况自定义
    if len(list_num)==0:
        list_num=-1

    return list_num

str1='adfabfjabcxhadalkjlabfjaecjadfjaaaaaaaaaaaababfjabgxweoiulkjkabfjabcxhgoiuer'
str2='abfjabc'
print('字符串所在位置:')
print(kmp(str1,str2))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值