首页 > 编程语言 >KMP算法详解

KMP算法详解

时间:2023-09-07 19:44:37浏览次数:39  
标签:s2 int S2 s1 next 算法 详解 KMP

呼——终于看懂了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;
}

标签:s2,int,S2,s1,next,算法,详解,KMP
From: https://www.cnblogs.com/jiangyuchen12/p/17685912.html

相关文章

  • 算法单元重启啦!
    开始跟着代码随想录重新学算法了,计划是按照它的目录一个专题一个专题地刷。我的文章目录会放在下面,按照自己的进度更新,整理出来一些有价值的基础知识和题解代码。使用语言是python,但知识点部分也会涉及C++。欢迎阅读点赞~目录数组链表......
  • LRUCache算法缓存策略(map+doubleLinkedList)
    packagearithmetic;importjava.util.HashMap;publicclassFaceTest81{//LRUcache缓存策略map+双向链表//get、update、put需要时间复杂度达到O1//map+双向链表结构publicFaceTest81(intcapacity){ cache=newMyCache(capacity);}privateMyCache<Integer,Intege......
  • 鸿蒙开发基础知识和环境搭建详解
    鸿蒙开发学习方案:学习基础知识:了解鸿蒙的基本概念和特点,包括其分布式架构、能力和开发理念。学习鸿蒙的开发环境搭建,包括安装开发工具和配置开发环境。学习鸿蒙应用开发:学习鸿蒙应用开发框架,包括应用程序生命周期、界面设计和布局、事件处理等。学习鸿蒙应用的数据存储和管理,包括文......
  • 详解canal同步MySQL增量数据到ES
    这篇文章,将使用canal将MySQL增量数据同步到ES 。如果想学Java项目的,强烈推荐我的......
  • 视频监控/安防监控/视频云存储EasyCVR平台设备分配模块升级详解
    安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台支持将部署在监控现场的前端设备进行统一集中接入,可兼容多协议、多类型设备,管理员可选择任意一路或多路视频实时观看,视频画面支持单画面、多画面显示,视频窗口数量有1、4、9、16个可选,还能支持视频轮巡播放。平台分发的视频流......
  • 2023“钉耙编程”中国大学生算法设计超级联赛(4)
    1003SimpleSetProblem题意:分别从k个集合中选一个元素组成一个数组\((a_1,a_2,a_3,...,a_k)\),求max\((a_1,a_2,a_3,...,a_k)\)-min\((a_1,a_2,a_3,...,a_k)\)的最小值。分析:我们给每个集合中的元素添加一个id标识它属于哪个集合,然后将所有集合合并并按数值大小从......
  • day24 - 回溯算法part01
    回溯算法理论基础 77. 组合classSolution{public:vector<vector<int>>result;vector<int>path;voiddfs(intn,intk,intstart){if(path.size()==k){result.push_back(path);return;}......
  • 视频监控/安防监控/视频云存储EasyCVR平台设备分配模块升级详解
    安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台支持将部署在监控现场的前端设备进行统一集中接入,可兼容多协议、多类型设备,管理员可选择任意一路或多路视频实时观看,视频画面支持单画面、多画面显示,视频窗口数量有1、4、9、16个可选,还能支持视频轮巡播放。平台分发的视频流......
  • Lnton羚通AI算法算力平台在海域可视化监管海域动态远程视频智能监管平台的构建方案
    一、方案背景随着科技的不断进步,智慧海域管理平台已成为海洋领域监管的关键工具。相比传统的视频监控方式,智慧海域管理平台通过建设近岸海域视频监控网、海洋环境监测网和海上目标探测网络等,实现了海洋管理的数字化转型。传统的监控方式需要大量人力物力,而智慧海域管理平台实现了......
  • 【C++】C++ 引用详解 ⑦ ( 指针的引用 )
    文章目录一、二级指针可实现的效果二、指针的引用1、指针的引用等同于二级指针(重点概念)2、引用本质-函数间接赋值简化版本3、代码示例-指针的引用一、二级指针可实现的效果指针的引用效果等同于二级指针,因此这里先介绍二级指针;使用二级指针作为参数,可......