Knuth-Morris-Pratt

简介: Knuth-Morris-Pratt“【5月更文挑战第19天】”

KMP(Knuth-Morris-Pratt)算法是一种高效的字符串搜索算法,用于在一个主串(text)中查找一个模式串(pattern)的匹配。KMP算法的核心在于预处理模式串,生成一个部分匹配表(也称为"前缀函数"或"部分失败函数"),这个表用于在搜索过程中遇到不匹配的情况时,能够快速确定下一步的搜索位置,从而避免了从主串的开头重新开始搜索。

KMP算法的关键步骤

  1. 预处理模式串:生成部分匹配表 ππ[i] 表示模式串从位置 0i 的最长的相同前缀和后缀的长度。
  2. 搜索过程:使用部分匹配表来确定在搜索过程中遇到不匹配字符时,模式串应该向右移动多远。

部分匹配表的构建

构建部分匹配表 π 的步骤如下:

  1. 初始化 π[0] = 0
  2. 对于 i1m-1(模式串的长度减1):
    • 如果 pattern[i-1] 等于 pattern[π[i-1]],则 π[i] = π[i-1] + 1
    • 否则,设置 j = π[i-1]
    • 循环直到找到 j > 0pattern[j-1] \neq pattern[i-1] 或者 j == 0
    • 如果 pattern[j-1] == pattern[i],则 π[i] = j
    • 否则,π[i] = 0

KMP搜索算法

  1. 初始化两个指针 i = 0(主串的当前位置)和 j = 0(模式串的当前位置)。
  2. i < n(主串的长度)且 j < m(模式串的长度)时:
    • 如果 text[i] == pattern[j],则 ij 都加1。
    • 如果 j == m,则找到一个匹配,记录匹配的开始位置,然后设置 j = π[j-1] 继续搜索下一个匹配。
    • 如果 text[i] \neq pattern[j]j > 0,则设置 j = π[j-1]
    • 如果 j == 0,则 i 加1。

KMP算法的示例代码(以C++为例)

#include <iostream>
#include <vector>
using namespace std;

// 构建部分匹配表
vector<int> computePartialMatchTable(const string& pattern) {
   
    int m = pattern.size();
    vector<int> π(m, 0);
    for (int i = 1; i < m; ++i) {
   
        int j = π[i - 1];
        while (j > 0 && pattern[i - 1] != pattern[j - 1]) {
   
            j = π[j - 1];
        }
        if (pattern[i - 1] == pattern[j - 1]) {
   
            π[i] = j + 1;
        }
    }
    return π;
}

// KMP搜索算法
void KMP(const string& text, const string& pattern) {
   
    int n = text.size();
    int m = pattern.size();
    if (m == 0 || n == 0 || m > n) return;

    vector<int> π = computePartialMatchTable(pattern);
    int i = 0, j = 0;

    while (i < n) {
   
        if (pattern[j] == text[i]) {
   
            i++;
            j++;
        }
        if (j == m) {
   
            cout << "匹配位置:" << i - j << endl;
            j = π[j - 1];
        }
        else if (i < n && pattern[j] != text[i]) {
   
            if (j != 0) {
   
                j = π[j - 1];
            } else {
   
                i++;
            }
        }
    }
}

// 测试代码
int main() {
   
    string text = "ABC ABCDAB ABCDABCDABDE";
    string pattern = "ABCDABD";
    KMP(text, pattern);
    return 0;
}

注意事项

  • KMP算法的时间复杂度为 O(n + m),其中 n 是主串的长度,m 是模式串的长度。
  • 构建部分匹配表是 KMP 算法的关键步骤,它决定了搜索过程中的效率。
目录
相关文章
|
12天前
|
JavaScript Java 关系型数据库
志愿者招募|基于SSM+vue的志愿者招募网站系统的设计与实现(源码+数据库+文档)
志愿者招募|基于SSM+vue的志愿者招募网站系统的设计与实现(源码+数据库+文档)
46 16
|
12天前
|
JavaScript Java 关系型数据库
废物回收机构|基于SprinBoot+vue的地方废物回收机构管理系统(源码+数据库+文档)
废物回收机构|基于SprinBoot+vue的地方废物回收机构管理系统(源码+数据库+文档)
54 18
|
12天前
|
JavaScript Java 关系型数据库
卤菜销售|基于SSM+vue的智能卤菜销售平台的设计与实现(源码+数据库+文档)
卤菜销售|基于SSM+vue的智能卤菜销售平台的设计与实现(源码+数据库+文档)
45 15
|
14天前
|
Java
Java一分钟之-并发编程:线程间通信(Phaser, CyclicBarrier, Semaphore)
【5月更文挑战第19天】Java并发编程中,Phaser、CyclicBarrier和Semaphore是三种强大的同步工具。Phaser用于阶段性任务协调,支持动态注册;CyclicBarrier允许线程同步执行,适合循环任务;Semaphore控制资源访问线程数,常用于限流和资源池管理。了解其使用场景、常见问题及避免策略,结合代码示例,能有效提升并发程序效率。注意异常处理和资源管理,以防止并发问题。
39 2
|
15天前
|
Java 开发者
Java一分钟之-高级集合框架:优先队列(PriorityQueue)
【5月更文挑战第18天】`PriorityQueue`是Java集合框架中的无界优先队列,基于堆数据结构实现,保证队头元素总是最小。常见操作包括`add(E e)`、`offer(E e)`、`poll()`和`peek()`。元素排序遵循自然排序或自定义`Comparator`。常见问题包括错误的排序逻辑、可变对象排序属性修改和混淆`poll()`与`peek()`。示例展示了自然排序和使用`Comparator`的排序方式。正确理解和使用`PriorityQueue`能提升应用性能。
48 6
|
15天前
|
存储 Java
Java一分钟之-高级集合框架:Queue与Deque接口
【5月更文挑战第18天】本文探讨Java集合框架中的`Queue`和`Deque`接口,两者都是元素序列的数据结构。`Queue`遵循FIFO原则,主要操作有`add/remove/element/peek`,空队列操作会抛出`NoSuchElementException`。`Deque`扩展`Queue`,支持首尾插入删除,同样需注意空`Deque`操作。理解并正确使用这两个接口,结合具体需求选择合适数据结构,能提升代码效率和可维护性。
46 4
|
6天前
|
JavaScript 前端开发 API
Vue.js
【5月更文挑战第27天】Vue.js
23 7
|
8天前
|
Cloud Native 持续交付 云计算
构建未来:云原生架构在现代企业中的应用与实践
【5月更文挑战第25天】 随着数字化转型的浪潮席卷全球,企业正面临着前所未有的挑战与机遇。云原生技术以其独特的弹性、可扩展性和敏捷性,成为推动企业技术创新的重要力量。本文将深入探讨云原生架构的核心概念,分析其在现代企业中的应用实例,并提出实施策略和最佳实践,以助力企业在激烈的市场竞争中占据先机。
|
5天前
|
XML 前端开发 Java
Model-View-Controller
“【5月更文挑战第28天】”
12 4
|
7天前
|
人工智能 vr&ar Android开发
移动应用与系统开发的未来趋势
【5月更文挑战第26天】随着移动互联网的飞速发展,移动应用与系统开发已成为技术创新的重要领域。本文将探讨当前移动应用开发的趋势、移动操作系统的演变以及未来可能的技术发展方向。通过分析跨平台工具的兴起、人工智能的融合以及安全性的重要性,我们旨在为开发者和决策者提供洞见,以便更好地适应不断变化的技术环境。

热门文章

最新文章