数据结构和算法笔记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 算法?
相关推荐
happygrilclh14 分钟前
高压高频电源的pid算法
算法
格林威20 分钟前
Baumer相机铸件气孔与缩松识别:提升铸造良品率的 6 个核心算法,附 OpenCV+Halcon 实战代码!
人工智能·opencv·算法·安全·计算机视觉·堡盟相机·baumer相机
葫三生27 分钟前
存在之思:三生原理与现象学对话可能?
数据库·人工智能·神经网络·算法·区块链
Evand J31 分钟前
【MATLAB例程】无人机三维路径规划|A*,RRT(快速随机树算法), APF(人工势场法)算法对比|可自定义起终点、障碍物坐标。附下载链接
算法·matlab·无人机·astar·路径规划·rrt·apf
嵌入小生00734 分钟前
双向链表、双向循环链表之间的异同---嵌入式入门---Linux
linux·c语言·数据结构·链表·嵌入式·小白
少许极端1 小时前
算法奇妙屋(二十七)-全排列与子集问题
算法·剪枝·回溯·递归
sali-tec1 小时前
C# 基于OpenCv的视觉工作流-章20-仿射变换
图像处理·人工智能·opencv·算法·计算机视觉
u0109272711 小时前
实时数据流处理
开发语言·c++·算法
独自破碎E1 小时前
【滑动窗口+计数】LCR015找到字符串中所有字母异位词
数据结构·算法
Trouvaille ~1 小时前
【Linux】线程同步与互斥(一):线程互斥原理与mutex详解
linux·运维·服务器·c++·算法·线程·互斥锁