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 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> KMP算法原理分析 -> 正文阅读

[数据结构与算法]KMP算法原理分析

前言

解决问题是字符串单模匹配。
其他算法可以参考博文链接

文本串S: dfgabcabcda
模式串T: abcabc

n为S的长度,即n = 11;
m为T的长度,即m = 6;

i为匹配时 S的下标;
j为匹配时T的下标。

对比:

在BF朴素算法的中每次匹配,如果匹配失败,i会从匹配开始前的i往后移动一位。j则会直接变为0
而在KMP算法中,将会被优化为i不会后退,j每次为使得模式串T与文本串S匹配的头部更加往后的一个下标

怎么实现呢?
先上代码:

代码

#include<iostream>
#include<string>
#include<vector>

#ifdef D
#define DBG(fmt,arg...) printf(fmt,##arg)
#else
#define DBG(fmt,arg...) {}
#endif

using namespace std;

vector<int> mynext;

void Getmynext(string s){
    int n = s.size();
    mynext = vector<int>(n,-1);
    mynext[0] = -1;
    mynext[1] = 0;
    DBG("NEXT = [ -1 0 ");
    for(int j = 2; j < n; ++j){
        if(mynext[j - 1] != 0 && s[mynext[j - 1]] == s[j - 1]){
            mynext[j] = mynext[j - 1]+1;
        }else if(s[0] == s[j - 1]){
            mynext[j] = 1;
        }else{
            mynext[j] = 0;
        }
        DBG("%d ",mynext[j]);
    }
    DBG("]\n");
    return ;
}

int KMP(string &A,string &B){
    int n = A.size();
    int m = B.size();
    if(n < m) return -1;
    int i = 0, j = 0;
    while(i < n && j < m){
        if(A[i] == B[j]){
            DBG("\033[32m while i = %d and j = %d, they are equaled !\033[0m\n",i,j);
            ++i;
            ++j;
        }else{
            DBG("\033[35;5m while i = %d and j = %d, they are noequaled !\033[0m\n",i,j);
            j = mynext[j];
            if(j == -1){
                ++i;
                j = 0;
            }
            DBG("\033[33mthen changed i = %d and j = %d!\033[0m\n",i,j);
        }
    }
    if(j >= m) return i - m;
    return -1;
}

int main(){
    string A,B;
    cin >> A >> B;
    Getmynext(B);
    DBG("\033[32mi get the vector next!\033[0m\n");
    int index = KMP(A,B);
    cout << "i find the model string in the index "<<index <<" of the main string !!"<<endl;
    return 0;
}

结果为:
在这里插入图片描述

分析

首先,需要理解next数组:
看代码。

不从原理往现象理解,我们从现象往原理理解。

构建问题环境:

文本串S: dfgabcabcda
模式串T: abcabc

n为S的长度,即n = 11;
m为T的长度,即m = 6;

i为匹配时 S的下标;
j为匹配时T的下标。

next数组的产生与意义

  • next数组是根据模式串T产生的。
    T= abcabc
    next数组为[-1 0 0 0 1 2]

  • next[j]代表什么呢?
    代表如果S的i和T的j没匹配上,那么在KMP算法中此时i应该再去和T中的哪个j比较?.
    可以看出,并没有打算让i从匹配起始位置往后移动一位,而是我都到这里了,我就不动了,,你模式串中的j找出一个来和我继续匹配。

比如 "abcdabce"“abce"匹配,第一次匹配i= 3,指向dj= 3指向e没匹配上,朴素匹配就会让i直接到i= 1,让j重新到0;
而KMP就会保持i = 3不变,找一个j来和我匹配。

next数组作用过程步步分析

  1. i = 0, j = 0;没匹配上,
    此时代码段中的 j = next[j];if(j == -1){i = i + 1; j = 0};生效,将i 变为1,就右变成next[0] = -1,然后j = 0;
  2. 看结果展示中绿色的调试信息,发现i = 3时开始匹配上。

next数组到底是什么?

可以看next数组的意义 ,next[j]就是此时i与j匹配失败时i不变的话,j 应该是多少?

此时满足的条件:

如果j== -1,说明i要和T的下标为-1出开始匹配。
如果j >= 0,说明i要和T下摆哦为next[j]出重新匹配。此时就满足的是,S中i往前next[j]- 1个字母与T中前next[j] - 1个字母相同

你把这个满足条件理解了,你就会发现从另一个方向理解了next数组。

就比如说下边这个很经典的结果,你看一下ij的变化就明白了。

在这里插入图片描述

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-27 11:31:56  更:2022-04-27 11:34:51 
 
开发: 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/26 6:29:21-

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