IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> [AcWing]831. KMP字符串(C++实现)KMP模板题 -> 正文阅读

[C++知识库][AcWing]831. KMP字符串(C++实现)KMP模板题

1. 题目

在这里插入图片描述

2. 读题(需要重点注意的东西)

思路:KMP的主要思路是如何通过已经比较的数,来减少两个字符串比较的次数。

接下来我会分析为什么可以减少比较的次数,这就是KMP的核心思想。

比较难以理解的地方就在于跳转的操作,这个操作只与p串本身有关,而与s串无关

跳转的操作本质上是一个求最大的相同前后缀长度的过程,每个字符串最大的相同前后缀长度即为p[i]不匹配时为跳
转的地方,如p串为ababab时(下标从1开始):

ne[1] = 0; 
ne[2] = 0;  最大的前缀为a,后缀为b
ne[3] = 1;  前缀为ab,后缀为ba时不等;前缀为a,后缀为a时相等,因此最大的相同前后缀长度为1
ne[4] = 2;  前缀为aba,后缀为bab时不等;前缀为ab,后缀为ab时相等,因此最大的相同前后缀长度为2

同理:

ne[5] = 3;
ne[6] = 4;

那么为什么求每个位置最大相同前后缀长度能减少比较次数呢?

我们看这样一种情况:(整个过程的视频演示在后面)
当比较到这样一种情况时:s[i] 与 p[j+1]不等了 ( 此时j=5 )
在这里插入图片描述

执行跳转操作,j = ne[5] = 3 ,相当于整个p串向后移动了
再比较 s[i] 和 p[j+1 = 4]的大小
在这里插入图片描述

我们可以看到,跳转后,绿色框中的值天生就是是完全相同的,不用再比较了
此时也只需要比较一位数即可,不用重新全部比较一遍
还是不同,再根据j = ne[3] = 1 跳转;比较s[i] 和 p[ j+1 = 2 ]
在这里插入图片描述

比较此时的s[i] 和 p[j+1]的大小,又失败了,那么直到跳转到j = 0,说明比较失败。
在这里插入图片描述

i此时再向前移动一位进行比较

在这里插入图片描述

---------------------------整个跳转过程的视频演示-------------------------------------
在这里插入图片描述


发现了吗?

i 只有当 ne 全部跳转完时,才会继续走到下一位进行比较。因此,只需要遍历一遍s串,就能够知道p串是否能匹配s串的子串。

这样,仅仅通过跳转,就减少了字符串比较的次数。

3. 解法

---------------------------------------------------解法---------------------------------------------------

#include <iostream>

using namespace std;

const int N = 100010, M = 1000010;

int n, m;
int ne[N];
char s[M], p[N];

int main()
{
    // ----------------输入开始--------------------------
    // cin >> n >> p+1 >> m >> s+1; 
    // 相当于以下四句代码
    cin >> n;
    for(int i = 1;i <= n;i++) cin >> p[i];
    cin >> m;
    for(int i = 1;i <= m;i++) cin >> s[i];
    // ----------------输入结束--------------------------
    
    // 构建ne数组,表示匹配不成功时可以直接向后跳多少位
    for (int i = 2, j = 0; i <= n; i ++ )
    {
        // 如果j不为0,且当前值不匹配,j跳转到ne[j]
        // p[i]前面的值可以不用比较,只需要比较p[i]和p[j+1],想想为什么?---KMP的核心
        while (j && p[i] != p[j + 1]) j = ne[j];
        // 如果当前值匹配,则可以继续匹配下一个值 i++ 和 j++
        if (p[i] == p[j + 1]) j ++ ;
        // 不匹配了,j此时是最大的前缀后缀相等的长度,将其赋值给ne[i],最大长度就是跳转的位置
        ne[i] = j;
    }
    
    // 匹配字符串
    for (int i = 1, j = 0; i <= m; i ++ )
    {
        // 如果j不为0,且当前s的值s[i]与当前p的值p[j+1]不匹配,j直接跳到到ne[j] 
        while (j && s[i] != p[j + 1]) j = ne[j];
        // 如果当前值匹配,继续匹配下一个值 j++
        if (s[i] == p[j + 1]) j ++ ;
        // 匹配成功
        if (j == n) printf("%d ", i - n);
    }

    return 0;
}

4. 可能有帮助的前置习题

5. 所用到的数据结构与算法思想

6. 总结

KMP算法模板题,推荐完全背下来。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-17 12:34:54  更:2021-11-17 12:37:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:04:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码