KMP算法

本文详细介绍Knuth-Morris-Pratt(KMP)算法的工作原理及其实现过程,通过具体实例展示了如何构建部分匹配表来提高字符串匹配效率。

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

字符串匹配算法,查找字符串。Knuth-Morris-Pratt算法

背景

一个字符串为“BBC ABCDAB ABCDABCDABDE”,问里面是否包含另一个字符串“ABCDABD”

算法

逐个搜索,为了提高效率使用《部分匹配表》

部分匹配表

例子一:

字符串: “bread”

**前缀(除最后一个字符所有的头部组合):**b, br. bre, brea

**后缀(除第一个字符所有的尾部组合):**read, ead, ad, d

搜索词bread
部分匹配词00000

- 字符串“b“的前缀和后缀为空集,共有元素的长度为0
- 字符串”br“的前缀为[b],后缀为[r],共有元素的长度为0
- 字符串”bre“的前缀为[b,br],后缀为[re,r],共有元素的长度为0
- 字符串”brea“的前缀为[b,br,bre],后缀为[rea,re,a],共有元素长度为0
- 字符串”bread“的前缀为[b,br,bre,brea],后缀为[read,rea,re,a],共有元素长度为0

例子二:

字符串:“ABCDABD”

  • 字符串”A“的前缀为[],后缀为[],共有元素长度为0
  • 字符串”AB“的前缀为[A],后缀为[B],共有元素长度为0
  • 字符串”ABC“的前缀为[A,AB],后缀为[BC,C],共有元素长度为0
  • 字符串”ABCD“的前缀为[A,AB,ABC],后缀为[BCD,CD,D],共有元素长度为0
  • 字符串”ABCDA“的前缀为[A,AB,ABC,ABCD],后缀为[BCDA,CDA,DA,A],共有元素长度为1
  • 字符串”ABCDAB“的前缀为[A,AB,ABC,ABCD,ABCDA],后缀为[BCDAB,CDAB,DAB,AB,B],共有元素长度为2
  • 字符串”ABCDABD“的前缀为[A,AB,ABC,ABCD,ABCDA,ABCDAB],后缀为[BCDABD,CDABD,DABD,ABD,BD,D],共有元素长度为0
搜索词ABCDABD
部分匹配值0000120

代码实现(Python3)

# -*- coding: utf-8 -*-


# 生成部分匹配表,用字典存储
def generate_dict_match(string_match):
    dict_match = {}
    for num in range(len(string_match)):
        # 字符串组合,‘A’、‘AB‘...’ABCDABD‘
        string_flag = string_match[:num + 1]
        # 前缀集合
        suffix_set = set(string_flag[num:]
                         for num in range(len(string_flag)) if num != 0)
        # 后缀集合
        prefix_set = set(string_flag[:num]
                         for num in range(len(string_flag)) if num != 0)
        # 交集元素的总长度
        string_lst = list(suffix_set & prefix_set)
        dict_match[num] = sum(len(item) for item in string_lst)

    return dict_match

# 遍历两个字符串
def find_string(string_origin, string_match):
    # 标记是否找到,默认未找到
    flag = False
    # 中间变量,存储原始字符串查找的起始位置
    index_origin = 0
    while index_origin < len(string_origin):
        index_flag = index_origin
        # 计数,如果等于string_match - 1,则表示找到
        count = 0
        for index_match in range(len(string_match)):
            if (string_origin[index_flag] != string_match[index_match]):
                break
            else:
                count += 1
                index_flag += 1
                # 找到匹配字串,退出循环
                if (index_match == len(string_match) - 1):
                    flag = True
                    break
        if count - dict_match[index_match] != 0:
            index_origin += count - dict_match[index_match - 1]
        else:
            index_origin += 1
    if flag == True:
        return index_origin - len(string_match) - 1
    else:
        return 0


if __name__ == "__main__":
    string_origin = "BBC ABCDAB ABCDABCDABDE"
    string_match = "ABCDABD"

    dict_match = generate_dict_match(string_match)
    position = find_string(string_origin, string_match)

    # 如果找到就输出第一个字母的位置
    if position != 0:
        print(position)
    else:
        print('Not Found')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值