算法回顾 - 查找文本串子序列

本文详细介绍了三种文本串子序列查找算法:暴力匹配、KMP算法和Boyer-Moore算法。通过对算法的描述和效率比较,阐述了每种算法的基本思路和关键点,如KMP的next跳转表和Boyer-Moore的Bad-character及Good-suffix跳转表。
摘要由CSDN通过智能技术生成

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/junxing2018_wu/article/details/108210839


有一个文本串T, 和一个模式串P, 现在要查找P在T中的位置, 怎么查找呢?

本文参数说明

  • target: 文本串
  • pattern: 模式串
  • i: 文本串target索引指针
  • j: 模式串pattern索引指针

[worst case] - 暴力匹配

  • 简单粗暴
  • 基本思路:
    • 逐个比较
      匹配成功时,i 右移一个位置(i=i+1),j 右移一个位置(j=j+1),继续比较…
      匹配失败时,i 右移一个位置(i=i-j+1),j 回到模式串起点(j=0),继续比较…
    • 直到 j 遍历完 pattern(匹配成功), 或者 i 遍历完 target (匹配失败)
    def violent_match(target: str, pattern: str):
     """
     暴力匹配
     """
     len_t, len_p = len(target), len(pattern)
     i, j = 0, 0
     while i < len_t and j < len_p:
         if target[i] == pattern[j]:
             # 如果当前字符匹配成功(即t[i] == p[j]), 则i++, j++
             i += 1
             j += 1
         else:
             # 如果失配(即t[i] != p[j]), 令i = i - (j - 1), j = 0
             i -= j - 1
             j = 0
    
     # 匹配成功, 返回模式串p在文本串t中的位置, 否则返回-1
     if j == len_p:
         return i - len_p
     else:
         return -1
    

[better case] - kmp 模式串匹配

  • 利用已经匹配过的信息,达到跳跃式匹配
  • 保持 i 指针不回溯, 只通过修改 j 指针, 让模式串尽量地移动到有效的位置
  • 基本思路:
    • 预先扫描模式串 pattern 生成 next 跳转表,指导 j 指针跳转(重难点)
    • 逐个比较
      匹配成功时,i 右移一个位置(i=i+1),j 右移一个位置(j=j+1),继续比较…
      匹配失败时,根据 next 跳转表决定 j 指针(下一次从 pattern 哪个位置开始比较)
    • 直到 j 遍历完 pattern(匹配成功), 或者 i 遍历完 target (匹配失败)
  • next跳转表 生成规则:
    • 简单说:只需求模式串 j 指针前面的字符串里前缀与后缀相同的最大长度 k
      理由:pattern[0 ~ k-1] == pattern [j-k ~ j-1] 等价于 此时 pattern 前 k 位已满足文本串
      比如:abcacb >>> [0, 0, 0, 0, 1, 0]

    • 特殊处理:

      • next 跳转表 首位为 -1。指针 j 已经在最左边了, 不可能再移动了, 这时候要 i 指针后移。
        故:abcacb >>> [-1, 0, 0, 0, 1, 0]
      • 避免出现 pattern[j] = pattern[ next[j] ],此时需要递归, k = pnext[k]
        比如:abab ==> [ -1, 0, 0, 1 ] 改成 [-1, 0, -1, 0]
    def kmp_match(target: str, pattern: str):
        """
        kmp 模式串匹配
        基本思路: 利用已经部分匹配这个有效信息, 
        保持i指针不回溯, 通过修改j指针, 让模式串尽量地移动到有效的位置
        每次匹配失败了, 根据next数组决定下一次从哪个位置开始匹配. 
        从而达到跳跃式匹配 
        """ python
        def gen_next(pattern: str):
            """
            生成指定模式串的next跳转表(循环)
            基本思路: 决定每次匹配失败时, 直接从哪个位置开始比较
            需要提前扫描模式串, 预先知道模式串的前缀与后缀相同的最大长度
            next 每一个元素 = 该元素之前的子串前缀与后缀相同的最大长度
            P[0, k-1] == P[j-k, j-1]  即 next[j] = k
            """
            # 模式串长度
            len_p = len(pattern)
            # 预设next跳转表都为0 (模式串没有相同子序列)
            pnext = [0 for i in range(len_p)]
            # j 已经在最左边了, 不可能再移动了, 这时候要 i 指针后移. 
            # 所以 next 首位为 -1,
            pnext[0] = -1
            k, j = -
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值