数据结构(Java版)- 串

227 阅读2分钟

Github仓库: JavaDataStructure: Java 版数据结构 (github.com)

1.串的模式匹配算法

1.1 BF算法

BF算法,即暴力(Brute Force)算法,是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。

1.1.1 代码

int index_BF(String S,String T){
    int lenS = S.length();
    int lenT = T.length();
    if(lenS < lenT) return -1;
    int i=0,j=0;
    while(i<lenS && j<lenT){
        if(S.charAt(i) == T.charAt(j)){
            i++;
            j++;
        }else{
            i = i-j+1;
            j = 0;
        }
    }
    if(j >= lenT){
        return i - lenT;
    }
    return -1;
}

1.1.2 例子

数据结构-串.png

1.1.3 分析

最好的情况

假设 S=“aaaaaaaba” T=“ba”

令主串的长度为 nn,子串的长度为 mm,假设从主串的第 ii 个位置开始与模式串匹配成功,则在前 i1i-1 趟中字符总共比较了 i1i-1 次;若第 ii 趟比较成功的字符比较次数是 mm 次,则总比较次数是 i1+mi-1+m 次。

最好情况下的平均比较次数为:

i=1nm+1pi(i1+m)=1nm+1i=1nm+1(i1+m)=12(n+m)\sum^{n-m+1}_{i=1}p_i(i-1+m)=\frac{1}{n-m+1}\sum^{n-m+1}_{i=1}(i-1+m)=\frac{1}{2}(n+m)

即最好情况下的平均时间复杂度为 O(n+m)O(n+m)

最坏的情况

假设 S=“aaaaaaaab” T=“aab”

假设从主串的第 ii 个位置开始匹配成功,则在前 i1i-1 趟匹配中字符总共比较了 (i1)×m(i-1)×m 次;若第 ii 趟匹配成功的比较次数为 mm 次,则总比较次数为 i×mi×m

最坏情况下的平均比较次数为:

i=1nm+1pi(i×m)=1nm+1i=1nm+1(i×m)=12m×(nm+2)\sum^{n-m+1}_{i=1}p_i(i \times m)=\frac{1}{n-m+1}\sum^{n-m+1}_{i=1}(i \times m)=\frac{1}{2}m \times (n-m+2)

即最坏情况下的平均时间复杂度为 O(n×m)O(n×m)

1.2 KMP 算法

KMP算法的改进之处在于每当一趟匹配过程中出现字符比较不等时,不需要回溯指针 i ,而是利用已得到的“部分匹配”的结果将模式向右“滑动”尽可能远的一段距离后,继续进行比较。

此算法可以在 O(n+m) 的时间数量级上完成串的模式匹配操作。

KMP的主要思想是当出现字符串不匹配时,可以知道一部分之前已经匹配的文本内容,可以利用这些信息避免从头再去做匹配了。

代码随想录——KMP

1.2.1 代码

int index_KMP(String S,String T){
    int lenS = S.length();
    int lenT = T.length();
    if(lenS<lenT || lenT==0) return -1;
    int[] next = getNext(T);
    int j = -1;
    for(int i=0;i<lenS;i++){
        while(j>=0 && S.charAt(i)!=T.charAt(j+1)){
            j = next[j];
        }
        if(S.charAt(i) == T.charAt(j+1)){
            j++;
        }
        if(j == lenT-1){
            return i - lenT + 1;
        }
    }
    return -1;
}

int[] getNext(String s){
    int n = s.length();
    int[] next = new int[n];
    int j = -1;
    next[0] = j;
    for(int i=1;i<n;i++){
        while(j>=0 && s.charAt(i)!=s.charAt(j+1)){
            j = next[j];
        }
        if(s.charAt(i) == s.charAt(j+1)){
            j++;
        }
        next[i] = j;
    }
    return next;
}

1.2.2 例子