数据结构和算法笔记6:KMP算法

KMP(Knuth-Morris-Pratt)算法是一种字符串匹配算法,用于在一个文本串中查找一个模式串的出现位置。它的主要优势在于在匹配过程中避免了不必要的回溯,提高了匹配效率。

KMP算法的核心思想是利用已经匹配过的信息,避免在模式串与文本串匹配过程中进行不必要的回溯。它通过构建一个部分匹配表(也称为失配函数),记录模式串中每个位置的最长可匹配前缀和后缀的长度,从而在匹配过程中通过查表来决定下一次匹配的位置。相关原理建议看文后的参考链接,讲得非常细致,可以先看3,再看1和2。

下面是KMP算法的代码实现(使用C++语言),下面是用KMP算法找寻text串中第一个pattern串的索引位置的代码:

cpp 复制代码
#include <iostream>
#include <vector>

using namespace std;

vector<int> buildPartialMatchTable(const string& pattern) {
    int m = pattern.length();
    vector<int> next(m, 0);
    int i = 1, j = 0;

    while (i < m) {
        if (pattern[i] == pattern[j]) {
            j++;
            next[i] = j;
            i++;
        } else {
            if (j != 0) {
                j = next[j - 1];
            } else {
                next[i] = 0;
                i++;
            }
        }
    }
    return next;
}

int kmpSearch(const string& text, const string& pattern) {
    int n = text.length();
    int m = pattern.length();
    if (m == 0) {
        return 0;
    }
    if (n == 0) {
        return -1;
    }
    
    vector<int> next = buildPartialMatchTable(pattern);
    int i = 0, j = 0;
    while (i < n) {
        if (text[i] == pattern[j]) {
            i++;
            j++;
            if (j == m) {
                return i - j;
            }
        } else {
            if (j != 0) {
                j = next[j - 1];
            } else {
                i++;
            }
        }
    }
    return -1;
}

int main() {
    string text = "sadbutsad";
    string pattern = "sad";
    
    int index = kmpSearch(text, pattern);
    if (index != -1) {
        cout << "Pattern found at index " << index << endl;
    } else {
        cout << "Pattern not found" << endl;
    }
    
    return 0;
}

上面是用while循环写的逻辑,可以使用for循环更简洁点:

cpp 复制代码
#include <iostream>
#include <vector>

using namespace std;

vector<int> buildPartialMatchTable(const string& pattern) {
    int m = pattern.length();
    vector<int> next(m, 0);
    int i = 1, j = 0;
    for (int i = 1; i < m; ++i)
    {
    	while (j > 0 && pattern[i] != pattern[j])
    		j = next[j - 1];
    	if (pattern[i] == pattern[j])
			++j;
		next[i] = j;
    }
    return next;
}

int kmpSearch(const string& text, const string& pattern) {
    int n = text.length();
    int m = pattern.length();
    if (m == 0) {
        return 0;
    }
    if (n == 0) {
        return -1;
    }
    
    vector<int> next = buildPartialMatchTable(pattern);
    int i = 0, j = 0;
    for (int i = 0; i < n; ++i)
    {
		while (i > 0 && text[i] != pattern[j])
			j = next[j - 1];
		if (text[i] == pattern[j])
			++j;
		if (j == m)
			return i - m + 1;
	}
    return -1;
}

int main() {
    string text = "sadbutsad";
    string pattern = "sad";
    
    int index = kmpSearch(text, pattern);
    if (index != -1) {
        cout << "Pattern found at index " << index << endl;
    } else {
        cout << "Pattern not found" << endl;
    }
    
    return 0;
}

输出:

KMP算法力扣相关的题目:

28. 找出字符串中第一个匹配项的下标

相关参考:

  1. 代码随想录-28. 实现 strStr()
  2. 【宫水三叶】简单题学 KMP 算法
  3. 灵茶山艾府的知乎回答:如何更好地理解和掌握 KMP 算法?
相关推荐
weixin_448119941 小时前
Datawhale DeepSeek Harness 技术入门与架构原理 笔记4
笔记·架构
lzhdim5 小时前
AI的分类
人工智能·算法·机器学习·分类·数据挖掘
凤凰院凶涛QAQ8 小时前
《Java版数据结构 & 集合类剖析》Map & Set & 反射:“从哈希碰撞到红黑树转换,反射帮你扒开 HashMap 的桶数组看个究竟”
java·数据结构·算法
H.莓飛8 小时前
【数据结构】排序_OJ题(一):计数、桶与排序后的处理
java·开发语言·数据结构
w_zero_one10 小时前
算法--模拟
java·数据结构·算法
秋天的怀念_David10 小时前
算法一千零一夜 · 第十三夜 幻方,武侠世界里的数学迷宫
java·程序人生·算法
秋天的怀念_David11 小时前
算法一千零一夜 · 第十四夜 幻方与奇妙的二进制
java·程序人生·算法
薛定e的猫咪11 小时前
(ICLR 2020)MAML 靠的不是快速学习,而是特征复用
人工智能·深度学习·学习·算法·机器学习
薛定e的猫咪12 小时前
(ICLR 2026)DF-META:面向 FJSP 的无导数元学习实例自适应调度
人工智能·深度学习·学习·算法·机器学习
果壳science13 小时前
张祥前实验如何获取正电荷
笔记·科技·嵌入式硬件·硬件工程·制造