ACM模板——KMP算法

简介: ACM模板——KMP算法

注释版v1

/*
    时间复杂度:如果文本串的长度为n,模式串的长度为m,那么匹配过程的时间复杂度为O(n),算上计算next的O(m)时间,KMP的整体时间复杂度为O(m + n)。
    算法说明:
            1、先通过目标串(ttr)计算出对应的首尾最长前后缀长度(next[])对应的值
            2、再通过计算出的(next[])“智能”处理目标串在主串中的匹配过程
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
/*
    功能:
        获取 next 数组的值:计算目标串前后缀相同的字符个数
    输入:
         ttr:目标串(下标从0开始)
        next:目标串的最长前缀和最长后缀相同的长度,[标记:长度]=>[-1:0],[0:1],[1:2],[n:n+1]。
              如:"ababaca",长度是7,所以next[0],next[1],next[2],next[3],next[4],next[5],next[6]分别计算的是 a,ab,aba,abab,ababa,ababac,ababaca 的相同的最长前缀和最长后缀的长度。
              由于 a,ab,aba,abab,ababa,ababac,ababaca 的相同的最长前缀和最长后缀是"","","a","ab","aba","","a",所以next数组的值是[-1,-1,0,1,2,-1,0]
        tlen:目标串长度
*/
void Get_Next(char *ttr,int *next,int tlen)
{
    next[0]=-1; // next[0] 初始化为 -1,-1 表示不存在相同的最大前缀和最大后缀
    for(int i=1,j=-1;i<tlen;i++)
    {
        while(j>-1 && ttr[j+1]!=ttr[i]) // 如果下一个不同,那么 j 就变成 next[j],注意 next[j] 是小于 j 的,无论 j 取任何值
            j=next[j]; // 往前回溯
        if(ttr[j+1]==ttr[i]) // 如果相同,j++
            j++;
        next[i]=j; // 这是把算好的 j 值(就是相同的最大前缀和最大后缀长度)赋给 next[i]
    }
}
/*
    功能:
        在主串中匹配目标串;代码和 Get_Next(...) 很类似
    输入:
         str:主串(下标从0开始)
        slen:主串长度
         ttr:目标串(下标从0开始)
        tlen:目标串长度
    输出:
        若存在,返回第一个字符匹配成功的位置(下标从0开始);否则,返回-1
*/
int Index_KMP(char *str,int slen,char *ttr,int tlen)
{
    int *next=new int[tlen];
    Get_Next(ttr,next,tlen);
    for(int i=0,j=-1;i<slen;i++)
    {
        while(j>-1 && ttr[j+1]!=str[i]) // ttr 和 str 不匹配,且 j>-1:表示 ttr 和 str 有部分匹配
            j=next[j]; // 往前回溯
        if(ttr[j+1]==str[i])
            j++;
        if(j==tlen-1) // 说明 j 移动到 ttr 的最末端,匹配完成(成功)
        {
            return i-tlen+1; // 返回相应的位置(首字符匹配的位置,下标从0开始)
        }
    }
    return -1; // 匹配失败
}
/*
    功能:
        目标串在主串中出现的次数(可重叠);代码和 Get_Next(...) 很类似
    输入:
         str:主串(下标从0开始)
        slen:主串长度
         ttr:目标串(下标从0开始)
        tlen:目标串长度
    输出:
        返回出现(匹配成功)的次数
*/
int Count_KMP(char *str,int slen,char *ttr,int tlen)
{
    int cnt=0;
    int *next=new int[tlen];
    Get_Next(ttr,next,tlen);
    for(int i=0,j=-1;i<slen;i++)
    {
        while(j>-1 && ttr[j+1]!=str[i]) // ttr 和 str 不匹配,且 j>-1:表示 ttr 和 str 有部分匹配
            j=next[j]; // 往前回溯
        if(ttr[j+1]==str[i])
            j++;
        if(j==tlen-1) // 说明 j 移动到 ttr 的最末端,匹配完成(成功)
        {
            //j=-1; // 无须此代码,因为通过 next[] 可处理 j 的值
            //i=i-tlen+1; // 无须此代码(主串往前回溯),因为通过 next[] 可处理这过程
            cnt++;
        }
    }
    return cnt; // 返回匹配成功的次数
}

简化版v1

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void Get_Next(char *ttr,int *next,int tlen)
{
    next[0]=-1;
    for(int i=1,j=-1;i<tlen;i++)
    {
        while(j>-1 && ttr[j+1]!=ttr[i])
            j=next[j];
        if(ttr[j+1]==ttr[i])
            j++;
        next[i]=j;
    }
}
int Index_KMP(char *str,int slen,char *ttr,int tlen)
{
    int *next=new int[tlen];
    Get_Next(ttr,next,tlen);
    for(int i=0,j=-1;i<slen;i++)
    {
        while(j>-1 && ttr[j+1]!=str[i])
            j=next[j];
        if(ttr[j+1]==str[i])
            j++;
        if(j==tlen-1)
            return i-tlen+1;
    }
    return -1;
}
int Count_KMP(char *str,int slen,char *ttr,int tlen)
{
    int cnt=0;
    int *next=new int[tlen];
    Get_Next(ttr,next,tlen);
    for(int i=0,j=-1;i<slen;i++)
    {
        while(j>-1 && ttr[j+1]!=str[i])
            j=next[j];
        if(ttr[j+1]==str[i])
            j++;
        if(j==tlen-1)
            cnt++;
    }
    return cnt;
}

注释版v2

/*
    功能:
        1、【标记 // Index】目标串在主串中首次匹配的索引值
        2、【标记 // Count】目标串在主串中出现的次数(可重叠)
    输入:
         str:主串(下标从0开始)
        slen:主串长度
         ttr:目标串(下标从0开始)
        tlen:目标串长度
    输出:
        1、【标记 // Index】返回首次匹配成功的索引值,否则返回 -1
        2、【标记 // Count】返回出现(匹配成功)的次数
    提示:
        next[i]:
       ----------------------------------------
            i 0 1 2 3 4 5 6 7
        模式串 A B C D A B D '\0'
       next[i] -1 0 0 0 0 1 2 0
*/
int kmp(char *str,int slen,char *ttr,int tlen)
{
//    int rs = 0; // Count
    int *next=new int[tlen+1]; // +1 是因为为了计算最长模式子串时的真前后缀相同长度
    next[0] =  -1;
    for (int i=0,j=-1;i<tlen;i++) // Get_Next
    {
        while (j!=-1 && ttr[i]!=ttr[j])
            j = next[j];
        next[i+1] = ++j;
    }
    for (int i=0,j=0;i<slen;i++) // Index_KMP or Count_KMP
    {
        while (j!=-1 && str[i]!=ttr[j])
            j = next[j];
        if (++j==tlen)
        {
//            rs++; // Count
            return i-j+1; // Index
        }
    }
//    return rs; // Count
    return -1; // Index
}

简化版v2

int kmp(char *str,int slen,char *ttr,int tlen)
{
//    int rs = 0; // Count
    int *next=new int[tlen+1];
    next[0] =  -1;
    for (int i=0,j=-1;i<tlen;i++)
    {
        while (j!=-1 && ttr[i]!=ttr[j])
            j = next[j];
        next[i+1] = ++j;
    }
    for (int i=0,j=0;i<slen;i++)
    {
        while (j!=-1 && str[i]!=ttr[j])
            j = next[j];
        if (++j==tlen)
        {
//            rs++; // Count
            return i-j+1; // Index
        }
    }
//    return rs; // Count
    return -1; // Index
}
目录
相关文章
|
4月前
|
算法
【算法】前缀和——二维前缀和模板题
【算法】前缀和——二维前缀和模板题
|
2月前
|
算法
第四章 KMP算法理论基础
第四章 KMP算法理论基础
22 0
|
2月前
|
算法
KMP算法
KMP算法
37 0
|
4月前
|
算法 C++
A : DS串应用–KMP算法
这篇文章提供了KMP算法的C++实现,包括计算模式串的next数组和在主串中查找模式串位置的函数,用于演示KMP算法的基本应用。
|
5月前
|
数据采集 算法 JavaScript
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
JavaScript字符串搜索涵盖`indexOf`、`includes`及KMP算法。`indexOf`返回子字符串位置,`includes`检查是否包含子字符串。KMP是高效的搜索算法,尤其适合长模式匹配。示例展示了如何在数据采集(如网页爬虫)中使用这些方法,结合代理IP进行安全搜索。代码示例中,搜索百度新闻结果并检测是否含有特定字符串。学习这些技术能提升编程效率和性能。
138 1
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
|
4月前
|
算法
KMP算法
KMP算法
35 0
|
5月前
|
设计模式 JavaScript 算法
vue2 原理【详解】MVVM、响应式、模板编译、虚拟节点 vDom、diff 算法
vue2 原理【详解】MVVM、响应式、模板编译、虚拟节点 vDom、diff 算法
194 0
|
5月前
|
算法 Java
KMP算法详解及其在字符串匹配中的应用
KMP算法详解及其在字符串匹配中的应用
|
15天前
|
算法
基于WOA算法的SVDD参数寻优matlab仿真
该程序利用鲸鱼优化算法(WOA)对支持向量数据描述(SVDD)模型的参数进行优化,以提高数据分类的准确性。通过MATLAB2022A实现,展示了不同信噪比(SNR)下模型的分类误差。WOA通过模拟鲸鱼捕食行为,动态调整SVDD参数,如惩罚因子C和核函数参数γ,以寻找最优参数组合,增强模型的鲁棒性和泛化能力。
|
1天前
|
供应链 算法 调度
排队算法的matlab仿真,带GUI界面
该程序使用MATLAB 2022A版本实现排队算法的仿真,并带有GUI界面。程序支持单队列单服务台、单队列多服务台和多队列多服务台三种排队方式。核心函数`func_mms2`通过模拟到达时间和服务时间,计算阻塞率和利用率。排队论研究系统中顾客和服务台的交互行为,广泛应用于通信网络、生产调度和服务行业等领域,旨在优化系统性能,减少等待时间,提高资源利用率。