首页 > 其他分享 >KMP

KMP

时间:2024-08-30 16:47:14浏览次数:13  
标签:int S2 s1 KMP next s2

呼——终于看懂了KMP——磕了三天了。

题目直达


Q: KMP是干什么的?

  • 是查找字符串用的,可以查找到 \(S2\) 字符串在 \(S1\) 字符串中出现的位置(当然,你可以统计出次数)。

Q: 那复杂度是多少的?

  • 通常,我们认为他的复杂度是 \(O(|S1|)\), 虽然有点常数。

常规的的比较方法是直接比较,枚举一个头,然后逐个比较,复杂度(喜提)\(O(|S1|\times|S2|)\)。慢就在于每次都要从头扫。很浪费时间 (浪费生命),那实在是太浪费了,有没有快点的办法呢?如果一个串,的开头已经确定了和我是一样的,那不就可以少用时间了吗?

我们希望(它/他/她)跳的尽可能远,但是不能漏掉,这样就可以节约大把的时间 (生命)。哪么可以找到 \(S2\) 对于每个 \(i( 1 \le i \le n)\) \(next_i\) 表示 \(S2[0, i - 1]\) 中最大 / 前缀和后缀相同 / 的长度,那么我们就可以在前缀匹配失败后跳转到后缀匹配。 \(next\) 数组之和 \(S2\) 相关, 所以可以预处理。

现在问题就变成了如何预处理上了。

假设红色[0 ~ j]的和橙色的 [i-j-1 ~ i-1] 已经匹配出来了,相等。那么接下来要匹配 \(j + 1\) 和 \(i + 1\)。假设最好情况 $ S2[j + 1] == S2[i]$, j++就好了。但是如果不等于呢?

那么我们就要比较[0, j - 1] 和 [i - j] 了, 但是又变回了 \(O(n ^ 2)\)。其实我们可以转换一下,反正橙色[i-j-1 ~ i-1]的和红色[0 ~ j]的一致,我们不妨把橙色的后缀移到前面来。

那么,这时我们就会发现我们要找的 \(j\) 应该变换的值我们之前求过是 \(next[j]\), 直接调用,但是为了避免没法匹配 while 就好了。


上代码吧,有注释的啦

#include <iostream>

using namespace std;

const int kMaxN = 1e6 + 5;

string s1, s2;
int l1, l2, net[kMaxN]; //最大前缀和后缀相同的长度, 因为next是关键词,所以用net替代

int main() {
    cin >> s1 >> s2;
    l1 = s1.size(), s1 = " " + s1; //舒服一点
    l2 = s2.size(), s2 = " " + s2; 
    int j = 0; //此时最长(既匹配到哪一位)
    for (int i = 2; i <= l2; i++) { //预处理
        while (j && s2[i] != s2[j + 1]) { //j已经为0就不用跳了
            j = net[j]; //不行就往回跳
        }
        if (s2[i] == s2[j + 1]) {//如果比较成功,j++
            j++;
        }
        net[i] = j;//赋值上
    }
    j = 0;
    for (int i = 1; i <= l1; i++) {
        while (j && s1[i] != s2[j + 1]) {
            j = net[j]; //匹配失败就往回跳
        }
        if (s1[i] == s2[j + 1]) { //如果比较成功,j++
            j++;
        }
        if (j == l2) { //成功就输出
            cout << i - l2 + 1 << '\n';
            j = net[j];
        }
    }
    for (int i = 1; i <= l2; i++) { //题目最后的要求
        cout << net[i] << ' ';
    }
    return 0;
}

标签:int,S2,s1,KMP,next,s2
From: https://www.cnblogs.com/JiCanDuck/p/18389052

相关文章

  • 代码训练营 Day9 | 151.翻转字符串里的单词 | 认识KMP算法
    151.翻转字符串里的单词这道题的难度在于如何高效率的处理空格对于python来说不能实现空间O(1)的复杂度,不过对于其他语言来说下面思路可以使用双指针方法同时指向数组的头部循环遍历整个字符串直到数组末尾快指针不能为空,因为快指针是要获取字母的,慢指针是用来获取新的字......
  • KMP-笔记
    tip:以下内容仅本人理解,如有问题,欢迎指出前言(?首先我们要知道KMP是干嘛的KMP是一个字符串匹配算法,相当于AC自动机的弱化版,如果你完全理解了KMP和Trie树的话,那你也离学会AC自动机不远了对于字符串匹配,我们有一个字符串和一个模式串,需要求字符串的子串里有没有这个模式串。......
  • 「字符串」前缀函数|KMP匹配:规范化next数组 / LeetCode 28(C++)
    概述为什么大家总觉得KMP难?难的根本就不是这个算法本身。在互联网上你可以见到八十种KMP算法的next数组定义和模式串回滚策略,把一切都懂得特别混乱。很多时候初学者的难点根本不在于这个算法本身,而是它令人痛苦的百花齐放的定义。有的next数组从0下标开始,有的从1开始;有的表......
  • 28:KMP算法
    KMP算法的用途是:在一个字符串中找到某一个字串的位置。时间复杂度是O(N)代码:packagealgorithmbasic.basicsets.class28;publicclassKMP{publicstaticintgetIndexOf(Strings1,Strings2){if(s1==null||s2==null||s1.length()<1||s2.......
  • 【杂乱笔记】Kmp字符串匹配算法
    KMP算法逻辑构建next数组:初始化next数组,用于存储每个位置的最长相同前后缀长度。遍历模式字符串patt如果当前字符与前缀字符匹配,增加前缀长度,并更新next数组。如果不匹配,使用next[prefix\_len-1]回退到上一个可能的前缀长度,继续比较。字符串匹配:初始......
  • 实现strStr() —— KMP算法(包含next数组的优化)
    目录KMP算法KMP算法的应用前缀表最长公共前后缀为什么要使用前缀表如何计算前缀表前缀表和next数组时间复杂度分析例题28.实现strStr构造next数组 使用next数组来做匹配 前缀表统一减一C++代码实现前缀表(不减一)C++代码实现总结 拓展:next数组的优化 KMP算......
  • KMP算法
    KMP算法介绍KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法,用于在主串(text)中查找模式串(pattern)。KMP通过预处理模式串,避免了在匹配失败时回溯主串,提高了匹配效率。其时间复杂度为O(n+m),其中n是主串的长度,m是模式串的长度。KMP算法的关键思想KMP算法的核心思想......
  • KMP算法——理解 next 数组
    !注意!本文与《王道》,《严书》有所不同,字符串均从第0位开始,next数组没有添加常数1。博客为梳理思路所用,难免纰漏,希望不吝赐教。在字符串匹配中,设m为待匹配的主串S长度,n为找寻的模式串T长度。如:在主串S='ababc'中寻找模式串T='abc'则字符串匹配算法返回S中第......
  • 子串查找算法KMP
    什么是子串查找        字符串子串查找是一种在较长的字符串(通常称为"主串"或"文本")中寻找一个较短字符串(称为"模式串"或"子串")的过程。这是计算机科学中的一个基本问题,在文本编辑、信息检索、生物信息学等多个领域都有广泛应用。主要的子串查找算法包括:暴力匹配法(B......
  • 从KMP到exKMP
    KMP(Knuth-Morris-Pratt)用途:用于一个文本串S内查找一个模式串P的出现位置,以及求一个字符串的最小循环元长度和最大循环次数。思路:\(kmp\)是对原始的在文本串S内查找一个模式串P的出现位置的一种优化。原始做法将\(s\)的每一位都与\(p\)的第一位开始匹配。(匹配到\(s\)的......