首页 > 编程语言 >kmp 算法

kmp 算法

时间:2023-06-14 10:35:04浏览次数:37  
标签:子串 ++ next int 算法 kmp now

问题描述

kmp算法解决的是字符串匹配问题,即:字符串P是否是字符串S的子串?如果是,它出现在s的哪些位置?这里我们称 S 为主串,P 为模式串。

思路

首先是暴力匹配算法(Brute-Force算法),代码如下:

void BruteForce(string s, string p) {
    int len_s = s.size(), len_p = p.size();
    for (int i = 0; i <= len_s - len_p; ++i) {
        int flag = true;
        for (int j = 0; j < len_p; ++j) {
            if (s[i + j] != p[j]) {
                flag = false;
                break;
            }
        }
        if (flag) {
            printf("pos = %d\n", i);
        }
    }
}

易得时间复杂度的最坏情况是$O(mn)$的,其中$n$为s的长度,$m$为p的长度。

为了降低字符串比较的复杂度,我们就必须降低比较的趟数,kmp算法的主要思想就是尽可能利用残余信息,即字符串如果在 j = r 处匹配失败了,那么前r个字符一定匹配成功了,暴力算法中,我们每次不匹配的情况下,都让j = 0,即模式串又从头开始匹配,这就完全没有利用比较带来的信息。

这里,我们可以找模式串的前缀子串和后缀子串,并得到对前r个字符组成的字符串,相等的前缀子串和后缀子串的最大长度,例如 p = "aabaac",那么对前$5$个字符,这个最大长度为2,所以对模式串 p 应该从 j = 2 处开始继续匹配,主串的 i 保持不变

因此,我们建立一个 next 数组,next[0] = 0next[k - 1] 表示前$k$个字符组成的字符串中,相等的前缀子串和后缀子串的最大长度,当 s[i] != p[j] 时,j = next[j - 1]

下一步就是求 next 数组,假设遍历到 j = x 时,这个最大长度为 now ,即 next[x - 1] = now,那么当 p[x] == p[now]next[x++] = ++now,如果 p[x] != p[now],那么 now = next[now - 1]

代码

快速计算next数组的代码:

void SetNext(vector<int> &next, string needle) {
    int x = 1, now = 0;
    while (x < needle.size()) {
        if (needle[x] == needle[now]) {
            next[x++] = ++now;
        } else if (now != 0) {
            now = next[now - 1];
        } else {
            next[x] = 0;
            x += 1;
        }
    }
}

基于next数组进行比较的代码

int strStr(string s, string p) {
    int m = p.size(), n = s.size();
    vector<int> next(m);
    SetNext(next, p);
    int i = 0, j = 0;
    while (i < n && j < m) {
        if (s[i] == p[j]) {
            ++i;
            ++j;
        } else {
            if (j > 0) {
                j = next[j - 1];
            } else {
                ++i;
            }
        }
    }
    if (j >= m) {
        return i - m;
    }
    return -1;
}

参考

kmp算法-阮行止

标签:子串,++,next,int,算法,kmp,now
From: https://www.cnblogs.com/zwyyy456/p/17479455.html

相关文章

  • 【基础算法】单链表的OJ练习(2) # 链表的中间结点 # 链表中倒数第k个结点 #
    前言对于单链表的OJ练习,<fontcolor=bluesize=4>需要深刻理解做题的思路</font>,这样我们才能够在任何场景都能够熟练的解答有关链表的问题。关于OJ练习(1):==->==传送门==<-==,其题目较为简单,思路也好理解,本章与(1)差不多,难度不大,<fontcolor=orangesize=4>核心点就在于理解解......
  • 马拉车算法
    截图来自董老师https://www.bilibili.com/video/BV173411V7Ai/?spm_id_from=333.999.0.0&vd_source=23dc8e19d485a6ac47f03f6520fb15c2  P3805【模板】manacher算法#include<iostream>#include<cstring>#include<cmath>#include<algorithm>#include......
  • 【VRP问题】基于遗传算法求解多约束多无人机灾情应急救援路径规划问题附matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • 多种智能优化算法运行时间和不同函数测试对比附matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • 《数据结构与算法》之二叉树(补充树)
    一.树结构之二叉树操作二叉树的查找二叉搜索树,也称二叉排序树或二叉查找树二叉搜索树:一棵二叉树,可以为空,如果不为空,应该满足以下性质:非空左子树的所有结点小于其根结点的键值非空右子树的所有结点大于其根结点的键值左右子树都是二叉搜索树对于二叉树的查找,其实沿用的是......
  • 文心一言 VS 讯飞星火 VS chatgpt (40)-- 算法导论5.4 4题
    四、一次聚会需要邀请多少人,才能让其中3人的生日很可能相同?文心一言:为了解决这个问题,我们需要先计算出所有可能的生日组合数,然后计算出其中生日相同的组合数。已知需要邀请的人数为:23人根据组合数公式,可计算出所有可能的生日组合数:2.58520167*10^{22}根据生日相同的组合......
  • 文心一言 VS 讯飞星火 VS chatgpt (40)-- 算法导论5.4 4题
    四、一次聚会需要邀请多少人,才能让其中3人的生日很可能相同?文心一言:为了解决这个问题,我们需要先计算出所有可能的生日组合数,然后计算出其中生日相同的组合数。已知需要邀请的人数为:23人根据组合数公式,可计算出所有可能的生日组合数:2.58520167*10^{22}根据生日相同的组合数公式,可......
  • .NET编译项目时出现《此实现不是 Windows 平台 FIPS 验证的加密算法的一部分》处理方
    此实现不是Windows平台FIPS验证的加密算法的一部分。”)的问题,如下图所示:对于上面的问题,只需要修改下注册表即可处理,方法如下:1、以管理员方式启动命令行工具后输入regedit,回车打开注册器;。2、打开注册表后,进入路径:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Co......
  • java常见的排序算法(冒泡排序、选择排序、插入排序、shell排序、归并排序、堆排序、快
    (文章目录)本文简单的介绍了java常见的几种排序。所有的排序均是一个数组由小到大进行排序。一、冒泡排序1、效率表现和适用范围效率O(n²)适用于排序小列表2、算法实现publicvoidbubbleSortArray(int[]a){ intn=a.length; for(inti=1;i<n;i++){ fo......
  • c#排序算法
    1.没有一种排序算法是万能的最快算法,因为最快的排序算法取决于数据的性质和排序要求。然而,对于一般情况下的排序问题,以下算法通常被认为是最快的:快速排序(QuickSort):这是一种基于分治思想的常见排序算法。其平均时间复杂度为O(nlogn)。因为其平均情况下时间复杂度相对较快,加上......