首页 > 其他分享 >kmp的神奇之处

kmp的神奇之处

时间:2024-05-26 12:11:01浏览次数:20  
标签:int s2 ne mid ++ kmp 神奇

$ kmp $ 想必大家都不陌生,这里先贴个模板hh

从0开始:

 for (int i = 1, j = 0; i < s2.length(); i++)
    {
        while (j && s2[i] != s2[j])
            j = ne[j - 1];
        if (s2[i] == s2[j]) j++;
        ne[i] = j;
    }
    for (int i = 0, j = 0; i < s1.length(); i++)
    {
        while (j && s1[i] != s2[j]) j = ne[j - 1];
        if (s1[i] == s2[j]) j++;
        if (j == s2.length())
            cout << i - s2.length() + 2 << '\n', j = ne[j - 1];
    }

对于从1开始:

for (int i = 2, j = 0; i <= m; i++)
{
    while (j && s2[i] != s2[j + 1])
        j = ne[j];
    if (s2[i] == s2[j + 1])
        j++;
    ne[i] = j;
}
for (int i = 1, j = 0; i <= n; i++)
{
    while (j && s1[i] != s2[j + 1])
        j = ne[j];
    if (s1[i] == s2[j + 1])
        j++;
    if (j == m - 1)
    {
        cout << i - m + 2 << endl;
        j = ne[j];
    }
}

这两者本质上没有什么区别,只不过是位置不同,当然,这只是字符串匹配,但是你知道吗?他还能做到这样一种事:两个数组,任意一段连续的区间,\(kmp\) 都能做到判断一个数组是否在这一段区间上整体大于等于或者整体小于等于,做法也是类似于上面的匹配模式,只是改了一下判断条件

这是题目

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 10, mod = 1e9 + 7;
signed main()
{
    std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int n; cin >> n;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++) cin >> a[i];
    vector<int> ne(2 * n + 1);
    vector<int> good(2 * n + 1);
    function<bool(int)> check;
    check = [&](int u) -> bool
    {
        if (2 * u - 1 > n) return false;
        for (int i = 1; i <= u; i++)
        {
            good[i] = i, good[2 * u - i] = i;
        }
        fill(ne.begin(), ne.end(), 0);
        for (int i = 2, j = 0; i <= 2 * u - 1; i++)
        {
            while (j && good[i] < good[j + 1]) j = ne[j];
            if (good[i] >= good[j + 1]) j++;
            ne[i] = j;
        }
        for (int i = 1, j = 0; i <= n; i++)
        {
            while (j && a[i] < good[j + 1]) j = ne[j];
            if (a[i] >= good[j + 1]) j++;
            if (j == 2 * u - 1) return true;
        }
        return false;
    };
    int l = 1, r = n;
    while (l < r)
    {
        int mid = (l + r + 1) >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    cout << l;
    return 0;
}

此外,如果需要求出从一段字符串的后缀匹配前缀的所有长度的话,其匹配方式还要稍作改变,在一般的模式中,\(ne[i]\) 表示的是包括i位置之前的所有字符串的匹配,而这样我们在求得过程中会进入死循环,所以要改变一下:

for (int i = 1, j = 0; i <  n; i++)
{
    while (j && s[i] != s[j]) j = ne[j];
    if (s[i] == s[j]) j++;
    ne[i + 1] = j;
}
for (int i =  n; i; i = ne[i])
    if (i <= n) ok[i]++;

这样就表示得是:从后缀得最后一个位置开始,他除了他自己以外能够匹配前缀得最长长度

标签:int,s2,ne,mid,++,kmp,神奇
From: https://www.cnblogs.com/o-Sakurajimamai-o/p/18213504

相关文章

  • 探索Linux中的神奇工具:深入了解find命令
    探索Linux中的神奇工具:深入了解find命令在Linux系统中,find命令是一个强大且灵活的工具,用于在文件系统中查找符合条件的文件和目录。本文将详细介绍find命令的基本用法和一些常见选项,帮助读者更好地理解和运用这个命令。了解find命令find命令用于在指定目录及其子目录中查找......
  • 【字符串常用算法】——KMP算法(你别闲烦 超详细,给你解释明白)
    1、字符串匹配——KMP算法    当我们想要想要在一个字符串中找到一个子串,如在字符串"aaabaaacaaad"中查找是否存在模式串"aaad"。首先常规的算法如下:1、先比较字符串与模式串 第一个是否相等,相等则匹配下一个2、比较第二个字符是否相等,相等则匹配下一个3、比......
  • 第二题-塔子哥的编译原理实验【KMP】
    本题的模式串可以展开,使用栈来模拟即可,每次一个(放入栈中对应的位置以及前面的数量,每次)弹出栈顶元素,然后将栈顶元素的数量乘以当前的字符串加上栈顶元素的前面的字符串加入到模式串中即可。需要注意有可能模式串非常长,所以中间需要判断是否已经超过了匹配串的长度,超过则直接返......
  • kmp算法java
    KMP是三位大牛:D.E.Knuth、J.H.Morris和V.R.Pratt同时发现的。其中第一位就是《计算机程序设计艺术》的作者!!KMP算法要解决的问题就是在字符串(也叫主串)中的模式(pattern)定位问题。说简单点就是我们平时常说的关键字搜索。模式串就是关键字(接下来称它为P),如果它在一个主串(接下来......
  • JAVA KMP 纯模板
    纯模板记忆使用~classMain{staticchar[]s1;staticchar[]s2;staticint[]next;publicstaticvoidmain(String[]args){Scannerin=newScanner(System.in);s1=in.nextLine().toCharArray();s2=in.nextLine().to......
  • 地理数据可视化的神奇组合:Python和Geopandas
    本文分享自华为云社区《Python与Geopandas:地理数据可视化与分析指南》,作者:柠檬味拥抱。地理数据可视化在许多领域都是至关重要的,无论是研究地理空间分布、城市规划、环境保护还是商业决策。Python语言以其强大的数据处理和可视化库而闻名,而Geopandas作为其地理信息系统(GIS)领域的......
  • 记字符串匹配KMP算法
    字符串匹配是一类经典的问题,在字符串s中找出模式串t第一个元素的下标,如果没有匹配到,则返回-1。此问题在leetcode中甚至归类为简单。解决此问题最直接的思路是使用暴力解法,从第0个元素开始逐个比较元素,当字符不匹配时,s的指针向前移动一位,不断重复。这种思路最简单且直接,但是无法通......
  • P5214 [SHOI2014] 神奇化合物
    题目链接:https://www.luogu.com.cn/problem/P5214题意:给定一张无向图,分别进行以下操作:Q:询问图中有多少连通块;Auv:代表在uv之间链接一条边;Duv:代表删除链接uv的边。做法:考虑到题目数据范围较小,直接用邻接表存边即可。可以发现有些点是不会进行改变的,可以讲在线询问转成......
  • KMP
    先放着点击查看代码 nxt[0]=-1; intj=0; for(inti=2;i<=len2;i++) { while(j&&s2[j+1]!=s2[i])j=nxt[j]; if(s2[j+1]==s2[i])j=j+1; nxt[i]=j; }//自己匹配 j=0; for(inti=1;i<=len1;i++) { stk[++top]=i; while(j&&s2[j+1]!=s1[i])j=nx......
  • 寻根KMP算法
    本人被\(KMP\)已经折磨许久。五战KMP。方知之前理解确实浅。故写此篇。这是之前那篇,实在是太浅,不过对代码做了注释。https://www.acwing.com/solution/content/131255/本篇重点说明\(KMP\)的原理,而非过程。过程相信其他博客已经写的十分完善了。\(KMP\)算法(\(Knuth-Morris-......