KMP字符串匹配算法

KMP字符串匹配算法

推荐一个讲解视频:B站KMP讲解视频

  KMP整个算法分为三个阶段,如下:
  (1) cal_next_1,计算待匹配字符串的前后缀数组next;
  (2) move_next,next右移一位,next[0] = -1
  (3)进行字符串匹配.
  其中在计算next数组时有两种方法,一个是比较简单的常规方法直接计算next数组,另一种是比较高阶的方法,两种都应该要掌握.

#include <iostream>
#include <vector>

using namespace std;

/**
 * 题目:KMP字符串匹配算法
 * 描述:使用KMP算法实现字符串匹配
 * 思路:1.计算next;2,.右移next;3.匹配字符串
 * 备注:掌握KMP
 */

//方法1:计算next数组,采用递推式的方法,效率更高
vector<int> cal_next_1(string needle) {
    int len = needle.length();
    vector<int> next(len, 0);
    next[0] = 0;
    int val = 0;
    int i = 1;
    while (i < len) {
        if (needle[i] == needle[val]) {
            val = val + 1;
            next[i] = val;
            i++;
        } else {
            if (val > 0) {
                val = next[val - 1];      //偏移映射
            } else {
                next[i] = 0;
                i++;
            }
        }
    }
    for (int i = 0; i < next.size(); i++) {
        cout << next[i] << " ";
    }
    cout << endl;
    return next;
}

//方法2:计算next数组,采用普通方法求解,效率较低,但易懂
vector<int> cal_next_2(string needle) {
    int len = needle.length();
    vector<int> next(len, 0);
    for (int i = 0; i < len; i++) {
        string substr = needle.substr(0, i + 1);
        int len_sub = substr.length();
        for (int j = len_sub - 1; j > 0; j--) {
            string sub_front = substr.substr(0, j);
            string sub_last = substr.substr(len_sub - j, j);
//            cout << sub_front << " " << sub_last << endl;
            if (sub_front == sub_last) {
                next[i] = j;
                break;
            }
        }
    }

    for (int i = 0; i < next.size(); i++) {
        cout << next[i] << " ";
    }
    cout << endl;
    return next;
}

//next数组向右移动一位
vector<int> move_next(vector<int> next) {
    int len = next.size();
    for (int i = len - 1; i > 0; i--) {
        next[i] = next[i - 1];
    }
    next[0] = -1;
    return next;
}

//KMP字符串匹配函数
void kmp_search(string haystack, string needle) {
    int len_1 = haystack.length();
    int len_2 = needle.length();

    vector<int> next1 = cal_next_1(needle);     //求next数组(简单版)
    vector<int> next2 = cal_next_2(needle);     //求next数组(增强版)

    vector<int> next = move_next(next1);        //next数组向右移动一位,next[0] = -1;

    //开始匹配
    int i = 0;  //指向 haystack 的下标
    int j = 0;  //指向 needle 的下标
    while (i < len_1) {
        if (j == len_2 - 1 && haystack[i] == needle[j]) {
            cout << "Find at " << i - j << endl;
            j = next[j];                        //继续往后匹配
        }
        if (haystack[i] == needle[j]) {         //匹配正确,j和i同时右移
            i++;
            j++;
        } else {
            j = next[j];                        //匹配错误,j回退到next[j]
            if (j == -1) {                      //如果j=-1,则j和i同时右移
                i++;
                j++;
            }
        }
    }

}

int main() {
    string haystack = "ABABABABCABAABABABCABAAD";
    string needle = "ABABCAB";
    kmp_search(haystack, needle);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值