美文网首页
寻找子串:BF算法、回溯算法、KMP算法

寻找子串:BF算法、回溯算法、KMP算法

作者: 青叶小小 | 来源:发表于2020-12-31 19:10 被阅读0次

一、前言

查找子串,是字符串查找的经典题目,大学就有!
比如:

主串:『ABAEABDACAADABACDDA』中查找
子串:『ABACD』

不考虑性能(时间、空间复杂度),大家可能就直接用暴力来求解了:Brute-Force(BF)、Back-Track(BT);但如果要求有一定的性能,那么 KMP 无疑是最经典的算法了(虽然不一定是效率最高的)

二、BF算法

// BF暴力算法
private static int bruteForce(String s, String p) {
    int i = 0;
    for (; i < s.length() - p.length() + 1; i ++) {
        int j = 0;
        for (; j < p.length(); j ++) {
            if (s.charAt(i + j) == p.charAt(j)) {
                continue;
            }
            break;
        }
        if (j == p.length()) {
            return i;
        }
    }
    return -1;
}

三、BT算法

// BT回溯算法
private static int backTrack(String s, String p) {
    int i = 0, j = 0;
    while (i < s.length() && j < p.length()) {
        if (s.charAt(i) == p.charAt(j)) {
            j ++;
        } else {
            i -= j;
            j = 0;
        }
        i ++;
    }
    return j == p.length() ? i - j : -1;
}

四、KMP算法

我们先来通过主串与子串的查找来找找规律:

image.png


再来看另一个数据多点的例子:
17084030-82e4b71b85a440c5a636d57503931415.png
『C』与『B』不匹配时,滑动子串,因为,有共同的前缀『AB』,所以,只需要从子串『index = 2』开始比较就行,如下图:
17084037-cc3c34200809414e9421c316ceba2cda.png
至此我们可以大概看出一点端倪,当匹配失败时,j要移动的下一个位置k。
存在着这样的性质:最前面的k个字符和j之前的最后k个字符是一样的

如果用数学公式来表示是这样的 :

P[0 ~ k-1] == P[j-k ~ j-1]

这个相当重要,如果觉得不好记的话,可以通过下图来理解(即 P[j]发生不匹配时,滑动到k的位置,比较P[k]):


17084056-66930855432b4357bafbf8d6c76c1840.png

主串S 与 子串P 在 j 处发生不匹配时,为什么可以移动到位置 k 推导:

  1. S[i] != P[j]时,必然存在:S[i-j ~ i-1] == P[0 ~ j-1];
  2. P中存在一个k,使得:P[0 ~ k-1] == P[j-k ~ j-1];
  3. 那么:S[i-k ~ i-1] = P[0 ~ k-1]

如果求 k ?我们需要借助一个数组,来记录当每个位置发生不匹配时,需要滑动到的位置,如下图:
Next 就是一个记录的数组(前缀数):

  • 初始标记: next[0] = -1;
  • next[k] = 相同前缀的字符个数;
  • 当 p[j] != p[k] 时, k = next[k] (直观就看下图:『C』和『B』)


    imagexxxx.png
// j为不匹配时的下标,k下标对应的是
// 串[0 ~ k-1] = 串[j-k ~ j-1]
private static int[] getNext(String p) {
    int next[] = new int[p.length()];
    int k = -1, j = 0;
    next[0] = -1;

    while (j < p.length() - 1) {
        if (k == -1 || p.charAt(j) == p.charAt(k)) {
            next[++j] = ++k;
        } else {
            k = next[k]; // next数组中前K个元素,已经有前缀统计
        }
    }
    return next;
}

KMP最终算法如下

// KMP算法
private static int kmp(String s, String p) {
    int next[] = getNext(p);
    int i = 0, j = 0;
    while (i < s.length() && j < p.length()) {
        if (j == -1 || s.charAt(i) == p.charAt(j)) {
            i ++;
            j ++;
        } else {
            j = next[j];
        }
    }
    return j == p.length() ? i - j : -1;
}

相关文章

  • 寻找子串:BF算法、回溯算法、KMP算法

    一、前言 查找子串,是字符串查找的经典题目,大学就有!比如: 主串:『ABAEABDACAADABACDDA』中查...

  • KMP算法文章合集

    字符串的查找:朴素查找算法和KMP算法 暴力匹配算法与KMP算法(串的匹配) 字符串查找算法BF和KMP 字符串匹...

  • KMP算法——寻找子串位置

    KMP算法——寻找子串位置 1、KMP算法简介: KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J....

  • BF(回溯)算法解析

    1 BF(回溯)算法 若看目标串T是否是源串S的子串,可采用BF算法,具体实现如下所示: 设T = “qwer”,...

  • 字符串匹配

    BF 算法和 RK 算法BM 算法和 KMP 算法

  • 学习BM算法的姿势

    BM算法简介 BM是字符串搜索算法。 字符串搜索单模式下有BF、RK、BM、KMP算法,其中BF是暴力搜索,RK是...

  • 字符串匹配算法总结

    面写过一篇字符串匹配算法,总共涉及BF算法,RK算法,BM算法,还有一种算法是KMP算法。这几种算法思想和代码我都...

  • 0x09KMP模式匹配

    KMP算法是对模式匹配算法的改进版,这个算法主要依靠子串中每个字符对应的next[j]的值,从而减少子串回溯的距离...

  • KMP字符串匹配算法

    KMP字符串匹配算法 先总结一下之前的几种字符串匹配算法 1 BF算法, 最简单的字符串匹配算法, 可以直接使用s...

  • 字符串匹配算法

    BF、BM、KMP算法详解 BF算法(Brute Force) 将模式串和主串进行比较,一致时则继续比较下一字符,...

网友评论

      本文标题:寻找子串:BF算法、回溯算法、KMP算法

      本文链接:https://www.haomeiwen.com/subject/dwjroktx.html