KMP字符串

给定一个模式串 SS,以及一个模板串 PP,所有字符串中只包含大小写英文字母以及阿拉伯数字。

模板串 PP 在模式串 SS 中多次作为子串出现。

求出模板串 PP 在模式串 SS 中所有出现的位置的起始下标。

输入格式

第一行输入整数 NN,表示字符串 PP 的长度。

第二行输入字符串 PP。

第三行输入整数 MM,表示字符串 SS 的长度。

第四行输入字符串 SS。

输出格式

共一行,输出所有出现位置的起始下标(下标从 00 开始计数),整数之间用空格隔开。

数据范围

1≤N≤1051≤N≤105
1≤M≤1061≤M≤106

输入样例:

3
aba
5
ababa

输出样例:

0 2
/*
 * 求s串在s1串中的循环节出现的起始下标
 */
#include "bits/stdc++.h"
using namespace std;
const int N = 1000005;
int n,m;
int ne[N];//求最长前后缀相等的长度
char s[N],s1[N];
int main() {
    cin >> n >> s + 1 >> m >> s1 + 1;
    for (int i = 2, j = 0; i <= n; i++) {
        while (j && s[i] != s[j + 1]) j = ne[j];
        if (s[i] == s[j + 1]) j++;
        ne[i] = j;
    }
    for (int i = 1, j = 0; i <= m; i++) {
        while (j && s1[i] != s[j + 1]) j = ne[j];
        if (s1[i] == s[j + 1]) j++;
        if (j == n) {
            cout << i - n << " ";
            j = ne[j];
        }
    }
    cout<<endl;
    return 0;
}

 

### KMP字符串匹配算法的原理 KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法,它通过构建部分匹配表(通常称为`next数组`),避免了传统暴力匹配中的重复比较操作。以下是KMP算法的核心原理: 1. **前缀和后缀的概念** 在模式串中,定义某个子串的最大公共前后缀长度。例如,在模式串 `aabaa` 中,子串 `aab` 的最大公共前后缀为 `a`,因此它的长度为 1。 2. **部分匹配表(Next 数组)** 部分匹配表记录了模式串中每个字符之前的部分所能达到的最大相同前后缀长度。这个表可以用来指导当发生失配时应该跳转到哪个位置继续匹配[^1]。 3. **减少回溯次数** 当发现当前字符不匹配时,利用已经计算好的 Next 数组来决定下一步从哪里重新开始匹配,而不是像朴素算法那样简单地移动一位并重试整个过程[^4]。 --- ### Python 实现 KMP 算法 下面是基于上述理论的一个完整的 Python 实现示例: #### 构建 Next 数组 ```python def build_next(pattern): next_array = [-1] * len(pattern) if len(pattern) > 0: next_array[0] = -1 k = -1 for q in range(1, len(pattern)): while k >= 0 and pattern[k + 1] != pattern[q]: k = next_array[k] if pattern[k + 1] == pattern[q]: k += 1 next_array[q] = k return next_array ``` #### 主函数实现 ```python def kmp_search(text, pattern): m = len(pattern) n = len(text) # 如果模式为空,则认为找到的位置是0 if m == 0: return 0 next_array = build_next(pattern) q = -1 for i in range(n): while q >= 0 and pattern[q + 1] != text[i]: q = next_array[q] if pattern[q + 1] == text[i]: q += 1 if q == m - 1: return i - m + 1 # 返回匹配起始索引 return -1 # 表示未找到 ``` --- ### Java 实现 KMP 算法 对于 Java 用户来说,也可以采用类似的逻辑实现 KMP 算法。下面是一个简单的例子: #### 构造 Next 数组 ```java public static int[] computeLPSArray(String pat) { int M = pat.length(); int lps[] = new int[M]; int length = 0; lps[0] = 0; int i = 1; while (i < M) { if (pat.charAt(i) == pat.charAt(length)) { length++; lps[i] = length; i++; } else { if (length != 0) { length = lps[length - 1]; } else { lps[i] = 0; i++; } } } return lps; } ``` #### 主函数实现 ```java public static int KMPSearch(String txt, String pat) { int N = txt.length(); int M = pat.length(); int lps[] = computeLPSArray(pat); int i = 0; // index for txt[] int j = 0; // index for pat[] while ((N - i) >= (M - j)) { if (pat.charAt(j) == txt.charAt(i)) { j++; i++; } if (j == M) { return i - j; // Match found at position i-j. } else if (i < N && pat.charAt(j) != txt.charAt(i)) { if (j != 0) { j = lps[j - 1]; } else { i = i + 1; } } } return -1; // No match found. } ``` --- ### 性能分析 相比于传统的暴力匹配方法 O((m-n+1)*n)[^2],KMP 算法的时间复杂度仅为 O(m+n),其中 m 和 n 分别表示文本串和模式串的长度。这是因为 KMP 利用了已有的匹配信息减少了不必要的回溯操作[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值