KMP算法中出现不匹配的文本转移背后的原因是什么?

2024-04-23

我一直在尝试理解KMP算法。但我仍然没有清楚地理解 kmp 算法背后的推理。假设我的文字是bacbababaabcbab模式是abababca。通过使用最长适当前缀的长度规则sub(pattern)与正确的后缀匹配sub(pattern),我填写了我的table[].

a b a b a b c a
0 0 1 2 3 4 0 1

现在我开始使用我的模式和表格对文本应用 KMP 算法。

到达上述文本的索引 4 后,我们有一个匹配项length(l)=5;通过看table[l-1]=3;根据 KMP 算法,我们最多可以跳过 2 个字符的长度并可以继续。

巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴巴
----xx|||
阿巴巴布卡

在这里我没有得到转变背后的逻辑。我们为什么要转变?有人可以澄清我的困惑吗?


要了解 KMP 算法背后的逻辑,您应该首先了解该 KMP 算法如何优于暴力算法。

Idea

模式发生转变后,朴素算法忘记了有关先前匹配符号的所有信息。因此它有可能一次又一次地将文本符号与不同的模式符号进行重新比较。这导致最坏情况的复杂度为 θ(nm)(n:文本长度,m:图案长度)。

Knuth、Morris 和 Pratt [KMP 77] 的算法利用了先前符号比较所获得的信息。它永远不会重新比较与模式符号匹配的文本符号。因此,Knuth-Morris-Pratt 算法的搜索阶段的复杂度为 O(n)。

然而,为了分析其结构,需要对模式进行预处理。预处理阶段的复杂度为O(m)。由于 m

文字:bacbababaabcbab 图案:abababca

在暴力法中, 将图案逐一滑动到文本上并检查是否匹配。如果找到匹配项,则再次滑动 1 以检查后续匹配项。

void search(char *pat, char *txt)
{
    int M = strlen(pat);
    int N = strlen(txt);

    /* A loop to slide pat[] one by one */
    for (int i = 0; i <= N - M; i++)
    {
        int j;

        /* For current index i, check for pattern match */
        for (j = 0; j < M; j++)
        {
            if (txt[i+j] != pat[j])
                break;
        }
        if (j == M)  // if pat[0...M-1] = txt[i, i+1, ...i+M-1]
        {
           printf("Pattern found at index %d \n", i);
        }
    }
}

上述算法的复杂度为O(nm)。 在上面的算法中我们从未使用过我们处理过的比较数据,

Bacbababaabcbab   //let I be iterating variable over this text

Abababca    //j be iterating variable over pattern

当 i=0 且 j=0 时,存在不匹配 (text[i+j]!=pat[j]),我们递增 i 直到出现匹配。 当 i =4 时,存在匹配(text[i+j]==pat[j]),递增 j 直到我们发现不匹配(如果 j=patternlength 我们找到模式),在给定的示例中,我们在 j= 处发现不匹配5 当 i=4 时,文本中的 idex 4+5=9 处发生不匹配。匹配的子字符串是 ababa , **

  • Why we need to choose longest proper prefix which is also proper suffix :

** 从上面:我们看到不匹配发生在 9 处,其中模式以子字符串 ababa 结尾。 现在,如果我们想利用迄今为止所做的比较,那么我们可以跳过(增量) i 超过 1,那么比较次数将减少,从而获得更好的时间复杂度。
现在我们可以利用经过处理的比较数据“ababa”获得什么优势。 如果我们仔细看:前缀aba字符串ababa与文本进行比较并匹配,后缀也是如此aba。但‘b’与‘a’不匹配

Bacbababaabcbab
         ||||||            
         ||||| x
        |||| ||
        ababab

但根据朴素的方法,我们将 i 增加到 5。但是通过观察我们知道,我们可以将 i = 6 设置为 aba 的下一次出现在 6 处。因此,我们不是与文本中的每个元素进行比较,而是对模式进行预处理用于查找最长的正确前缀,它也是正确的后缀(称为边界)。在上面的“ababa”示例中,最长边框的长度为 3(即aba)。因此增加:子字符串的长度 - 最长边框的长度 -=> 5-3 =2。
如果我们的比较在 aba 处失败,则最长边界的长度为 1 并且 j=3,因此增加 2 。

有关如何预处理的更多信息:http://www-igm.univ-mlv.fr/~lecroq/string/node8.html#SECTION0080 http://www-igm.univ-mlv.fr/~lecroq/string/node8.html#SECTION0080 http://www.inf.fh-flensburg.de/lang/algorithmen/pattern/kmpen.htm http://www.inf.fh-flensburg.de/lang/algorithmen/pattern/kmpen.htm

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

KMP算法中出现不匹配的文本转移背后的原因是什么? 的相关文章

  • 在某些情况下,直接访问字符串的后备数组是否合理?

    我正在致力于优化文本处理软件 其中经常使用以下类 class Sentence private final char textArray private final String textString public Sentence Str
  • 在 O(n) 时间内运行的指数乘法算法?

    我正在读一本算法教科书 我被这个问题难住了 假设我们要计算值 x y 其中 x 和 y 为正数 分别具有 m 和 n 位的整数 解决该问题的一种方法是执行 y 1 乘以 x 你能给出一个仅使用 O n 乘法步骤的更有效的算法吗 这会是一个分
  • 如何在 Bash 中将字符串转换为小写

    有办法进去吗bash questions tagged bash将字符串转换为小写字符串 例如 如果我有 a Hi all 我想将其转换为 hi all 有多种方法 POSIX标准 https en m wikipedia org wiki
  • C++中字符串如何分配内存?

    我知道动态内存比设置固定大小的数组并使用其中的一部分具有优势 但在动态内存中 您必须输入要在数组中存储的数据量 使用字符串时 您可以输入任意数量的字母 您甚至可以使用字符串代替数字 然后使用函数来转换它们 这一事实让我认为字符数组的动态内存
  • PostgreSQL 对 string\varchar 的各种清理

    我必须通过以下方式清理一些 varchar 删除特殊字符 例如 来自封闭列表 我已经成功地通过大量使用replace regexp replace来做到这一点 但我正在寻找类似于SQL Server中的东西 删除以下数字但不删除相邻的数字含
  • 给定与总和匹配的长度的唯一 3 位数字 (-1,0,1) 序列的数量

    假设您有一个长度为 n 即空格数 的垂直游戏板 你有一个三面骰子 有以下选项 前进一 停留和后退 如果您低于或高于棋盘游戏空间的数量 则该游戏无效 一旦到达棋盘末端 唯一有效的动作就是 停留 给定确切的骰子投掷次数 t 是否可以通过算法计算
  • Java:使用indexOf方法根据另一个数组对数组进行排序

    我想根据另一个数组 索引 的排序顺序迭代两个数组 A B 在本例中为 10 34 32 21 String A a b c d String B e f g h int indexes 10 34 32 21 为这里的坏例子道歉 我已经更新
  • 为无向无权图实现推重标签算法 s-t 最小割边

    我正在寻找一个好的解决方案来在无向和未加权图中找到 s t 最小切割边 我想使用推送重新标记算法 但我不确定如何实现它以在无向和未加权图上找到最小割 在每对顶点之间有两条反向边 并在所有边上赋予相同的权重 并应用推送重新标记算法 我可以用这
  • 以一定角度遍历二维数组

    通常我们按行或列遍历数组 但这里我想以角度遍历它 我会尝试解释我的意思 因此 假设角度是 45 度 那么它会搜索为 0 0 then 0 1 1 0 then 0 2 1 1 2 0 等等 抱歉 无法上传图像 因为我是新用户 不允许这样做
  • 使用 string.whitespace 删除 Python 中的空格

    Python 的 string whitespace 很棒 gt gt gt string whitespace t n x0b x0c r 如何在不手动输入 t n 等正则表达式的情况下将其与字符串一起使用 例如 它应该能够转动 请不要伤
  • 如何使用KDTrees实现最近邻搜索?

    所以 我正在实施一个KD Tree http en wikipedia org wiki Kd tree进行最近邻搜索 我已经构建了树部分 但我认为我没有完全理解搜索部分 关于遍历树来搜索邻居 维基百科文章如下 Starting with
  • Bellman-Ford 算法检测什么?负重还是负循环?

    如果给定一个图 现在我们要从源头计算最短路径 现在 如果一条边具有负权重 但在到达目的地时有边到后边返回到该边 我的意思是如果没有循环 那么我们就没有负循环 但是here http en wikipedia org wiki Bellman
  • 如何将运算符作为分隔符拆分数学表达式,同时将它们保留在结果中?

    我需要拆分一个表达式 例如 a b c d e and get a b c d e分别 作为字符串数组 以及 d 也是一个运算符数组 分别 我尝试过 String myString String myString a b c d e Str
  • 两个非嵌套循环的大 O 表示法

    对于两个非嵌套的 for 循环 大 O 表示法是什么 Example for int i 0 i
  • 在无向图中查找强连通分量

    我想在无向图中找到强连接的组件 即如果我从节点开始A然后我会回到节点A并且每条边都被恰好访问一次 对于有向图可以使用Tarjan算法来寻找强连通分量 但是对于无向图怎么办 我认为您错过了强连通分量的含义 强连接组件 如果所有顶点对之间都存在
  • 合并字符数组中的最小重复次数

    假设我有两个数组 我想合并它们 以便合并后的数组具有最小重复次数 例如 x x 是重复 arr1 x d d m f m arr2 d d x f f m 唯一的条件是在合并数组中 元素来自arr1 and arr2必须出现在各自的订单中a
  • 反转二进制网络

    如何反转二元方程 以便找到哪些输入将产生给定的输出 Example Inputs i0 through i8 Outputs o0 through o8 Operators XOR AND 二元方程 1 i0 1 i1 0 i2 1 i3
  • 无需时间即可生成随机字符串?

    我知道如何使用 Runes 和播种 rand Init 在 go 中生成随机字符串time UnixNano 我的问题是 是否可以 使用 stdlib 在不使用当前时间戳 安全 的情况下播种 rand 此外 我问 因为仅仅依靠时间来为敏感操
  • 从剪贴板获取文本后将一个字符串插入另一个字符串所需的建议

    简介及相关信息 我有一个edit control只需要接受带符号的十进制数 类似于 12 35 我决定通过以下方式实现这一点subclassing The WM CHAR处理程序似乎运行良好 我需要处理其他几条消息以完全保护用户免于输入无效
  • Java 9 中紧凑字符串和压缩字符串的区别

    有什么优点紧凑的字符串 http openjdk java net jeps 254JDK9 中的压缩字符串 压缩字符串 Java 6 和紧凑字符串 Java 9 都有相同的动机 字符串通常实际上是 Latin 1 因此浪费了一半的空间 和

随机推荐