📜  门|门CS 2010 |第 52 题(1)

📅  最后修改于: 2023-12-03 15:28:48.817000             🧑  作者: Mango

门|门CS 2010 |第 52 题

这是一道门门CS2010年的编程题,需要完成一个简单的字符串匹配程序,能够在长文本中找到给定模式串的位置。

题目描述

给定一个长字符串 text 和一个模式串 pattern,需要找到模式串在长字符串中的起始位置。

输入格式

第一行输入一个整数 T,表示测试数据的组数。

每组测试数据包含两行,第一行为长字符串 text,第二行为模式串 pattern,两者长度均不超过 $10^5$。

输出格式

对于每组测试数据,输出一行,表示模式串在长字符串中的起始位置。若模式串不在长字符串中,则输出 -1。

样例输入
2
aabcabcabcabcabda
abcabcab
abckhabcabcabxabcay
abcabcab
样例输出
2
7
解题思路

这里提供两种常见的字符串匹配算法:暴力法和KMP算法。

暴力法

暴力法的基本思想是对长字符串中每个可能匹配到模式串的位置进行匹配,最坏情况下需要进行 $O(nm)$ 次比较,其中 $n$ 表示长字符串长度,$m$ 表示模式串长度。

实现时,可以使用两个指针 $i$ 和 $j$ 分别指向长字符串和模式串的当前位置,进行逐一比较。如果匹配成功,将 $i$ 指向下一个位置,$j$ 重新指向模式串开头;否则将两个指针同时向后移动一位。

def search(text, pattern):
    n, m = len(text), len(pattern)
    for i in range(n - m + 1):
        j = 0
        while j < m and text[i+j] == pattern[j]:
            j += 1
        if j == m:
            return i
    return -1
KMP算法

KMP算法的基本思想是利用已经匹配成功的部分来避免重复匹配,在最坏情况下只需要进行 $O(n)$ 次比较。

实现时需要先预处理出模式串的next数组,表示在模式串中,每个前缀的最长相同前缀后缀长度。

def compute_next(pattern):
    m = len(pattern)
    next = [0] * m
    i, j = 1, 0
    while i < m:
        if pattern[i] == pattern[j]:
            i += 1
            j += 1
            next[i-1] = j
        elif j > 0:
            j = next[j-1]
        else:
            i += 1
    return next

然后利用next数组进行匹配,指针 $i$ 表示长字符串中当前匹配的位置,指针 $j$ 表示模式串中当前需要匹配到的位置。若匹配成功,则将两个指针同时向后移动一位,否则根据next数组移动模式串指针的位置。

def search_kmp(text, pattern):
    n, m = len(text), len(pattern)
    next = compute_next(pattern)
    i, j = 0, 0
    while i < n and j < m:
        if text[i] == pattern[j]:
            i += 1
            j += 1
        elif j > 0:
            j = next[j-1]
        else:
            i += 1
    return i - m if j == m else -1
总结

字符串匹配是一类经典的问题,在实际工作中经常需要用到。暴力法和KMP算法是两种常见的实现方式,可以根据数据规模和实现复杂度进行选择。