KMP算法

字符串匹配最基础的算法是一个字符一个字符的匹配,若当前不匹配则指针指向下一个字符。基础算法的写法为:

int findString(string &s, string &t){
    int slen = s.size();
    int tlen = t.size();
    if (slen < tlen) {
        return -1;
    }
    int j = 0;
    for (int i = 0;i < slen;i++) {
        int tmp = i;
        for (j = 0;j < tlen;j++) {
            if (s[tmp] == t[j]) {
                tmp++;
            }
            else {
                break;
            }
        }
        if (j == tlen) {
            return i;
        }
    }
    return -1;
}

还有一种Rabin-Karp算法这种算法的基础思想是把字符串转为数字,这是一种很奇妙的算法,但是我不是很喜欢,因为对于ABC这种如果我们把他转为数字A对应1,B对应2,…K对应11。
那么111可以为AAA,也可以为AK,也可以为KA。参考题目https://leetcode.com/problems/decode-ways/#/description
因此在此不做叙述。
KMP算法是一种比较经典的算法,其重点在于匹配表的建立。匹配表是指对字符串p,p0p1…pk = pj - kpj - k + 1…pj则p[j + 1] = k.这么设计的原因是:
s0 s1 s2 …sk…sj-k sj-k+1 …sj sj+1…sn
p0p1…pk…pj-k pj-k+1…pj pj+1…pm
如果pj+1 != sj+1那么,p可以向前移动k个单位保证s[j-k…j] = p[0…k]
这样减少了一部分不必要的匹配。
KMP算法的代码如下:

void createPrefix(string &s, vector<int> &nexts) {
    if (s.size() != nexts.size()) {
        return;
    }
    nexts[0] = -1;
    int k = -1, j = 0;
    while (j < s.size() - 1) {
        if (k == -1 || s[j] == s[k]) {
            k++;
            j++;
            //这里很关键p[j] != p[next[j]]
            if (nexts[j] != nexts[k]) {
                nexts[j] = k;
            }
            else {
                nexts[j] = nexts[k];
            }
        }
        else {
            k = nexts[k];
        }
    }
}

int findStringKMP(string &s, string &t) {
    vector<int> tPre(t.size(), 0);
    createPrefix(t, tPre);
    int i = 0, j = 0;
    int slen = s.size(), tlen = t.size();
    while (i < slen && j < tlen) {
        if (j == -1 || s[i] == t[j]) {
            i++;
            j++;
        }
        else {
            j = tPre[j];
        }
    }
    if (j == tlen) {
        return i - j;
    }
    return -1;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值