KMP的next数组构建详解

KMP的next数组构建详解

1. next数组的作用
  • 核心功能:在KMP算法中,当模式串与主串发生不匹配时,next数组决定模式串指针回退的位置,避免无效匹配。

  • 定义next[i]表示子串s[0...i]的最长公共前后缀长度。例如,"ABAB"next[3] = 2(前缀AB和后缀AB)。

2. 代码逐行解析
void getNext(int* next, const std::string& s) {
    int j = 0;            // j指向前缀末尾,初始为0
    next[0] = j;          // 第一个字符无前后缀,长度为0
    for (int i = 1; i < s.size(); i++) {  // 从第二个字符开始处理
        // 不匹配时,通过next数组回溯j
        while (j > 0 && s[i] != s[j]) {  
            j = next[j - 1];  // 关键:利用已计算的next值回退
        }
        // 匹配时,j后移
        if (s[i] == s[j]) {
            j++;
        }
        // 记录当前i对应的最长公共前后缀长度
        next[i] = j;
    }
}
3. 关键问题:为什么用while循环回退?
  • 逐步缩短前缀:当s[i]s[j]不匹配时,需找到更短的公共前后缀继续尝试。例如,模式串"ABABAC",在i=5(字符C)时,若j=3(字符B),此时需回退到next[2]=1(字符A)继续比较。

  • 避免遗漏:使用while确保所有可能的前缀都被尝试,直到匹配或退到0。若用if,仅回退一次,可能错过有效前缀。

4. 实例演示

模式串"ABABAC"
步骤分析

is[i]初始jwhile循环过程最终jnext[i]解释
0A0-00初始化
1B0不匹配,j保持000AB无公共前后缀
2A0s[2]=A匹配s[0]11ABA最长公共"A"
3B1s[3]=B匹配s[1]22ABAB最长公共"AB"
4A2s[4]=A匹配s[2]33ABABA最长公共"ABA"
5C3两次回退到j=000ABABAC无公共前后缀

最终next数组[0,0,1,2,3,0]

5. 完整KMP搜索示例
int kmpSearch(const string& text, const string& pattern) {
    int n = pattern.size();
    if (n == 0) return 0;
    int* next = new int[n];
    getNext(next, pattern);

    int j = 0;  // 模式串指针
    for (int i = 0; i < text.size(); i++) {  // i遍历主串
        // 不匹配时,回退模式串指针
        while (j > 0 && text[i] != pattern[j]) {
            j = next[j - 1];
        }
        // 匹配时,后移j
        if (text[i] == pattern[j]) j++;
        // 完全匹配时返回起始位置
        if (j == n) {
            delete[] next;
            return i - n + 1;
        }
    }
    delete[] next;
    return -1;
}

使用示例

int main() {
    string text = "ABABABACABABAC";
    string pattern = "ABABAC";
    int pos = kmpSearch(text, pattern);  // 输出:Pattern found at index 2
    // 解释:text[2..7] = "ABABAC"与模式匹配
}
6. 总结
  • 核心思想:通过模式串自我匹配构建next数组,利用已匹配信息避免重复比较。

  • 时间复杂度:O(n+m),n和m分别为模式串和主串长度,远优于暴力法的O(nm)。

  • 关键点:理解next数组的动态构建过程,以及如何通过回溯高效寻找最长公共前后缀。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值