📜  门| GATE-CS-2016(套装1)|第 48 题(1)

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

GATE-CS-2016 (套装1) | 第 48 题

这是一道算法题,要求实现一种字符串搜索算法。以下是关于这道题的介绍和解法。

问题描述

给定一个文本串 T 和一个模式串 P,要求在文本串中查找模式串,并返回模式串在文本串中的起始位置。

解法
Brute-Force 算法

最简单的算法是 Brute-Force,也称为朴素算法。它的想法是从文本串的第一个字符开始,依次比较每个字符是否与模式串相同。如果匹配失败,则移到下一个字符重新开始匹配。这个算法的时间复杂度是 O(nm),其中 n 是文本串的长度,m 是模式串的长度。

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

Brute-Force 算法的时间复杂度比较高,有人提出了 KMP 算法来优化。这个算法的基本思路是对模式串进行预处理,以便在匹配的过程中快速地跳过无需比较的字符。这个算法的时间复杂度是 O(n+m)

KMP 算法使用一个 next 数组来保存匹配失败时模式串应该移动到哪一个位置开始继续匹配。next[j] 表示模式串中第 j 个字符前面的一个子串的最长公共前后缀的长度(不包括第 j 个字符)。举个例子,如果模式串是 ababac,则 next[5] = 2,因为 ababa 的最长公共前后缀,并且这个前缀也是以 b 结尾的。算法的流程如下所示。

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


def search(T, P):
    n, m = len(T), len(P)
    next = compute_next(P)
    i, j = 0, 0
    while i < n and j < m:
        if j == -1 or T[i] == P[j]:
            i += 1
            j += 1
        else:
            j = next[j]
    if j == m:
        return i - j
    else:
        return -1
Boyer-Moore 算法

除了 KMP 算法之外,还有一个比较著名的字符串搜索算法叫做 Boyer-Moore 算法,它的时间复杂度可以达到 O(n/m)。Boyer-Moore 算法的基本思路是尽可能地跳过文本串中的无需匹配的字符。

Boyer-Moore 算法使用两个规则来决定如何跳过字符。第一个规则是“坏字符规则”,也就是文本串中的一个字符如果不在模式串中,则文本串可以跳过这个字符及其前面的所有字符。第二个规则是“好后缀规则”,如果在模式串中某个后缀能够和文本串中匹配的子串匹配成功,则可以直接跳到这个后缀的前面进行匹配。

def compute_bad_char(P):
    m = len(P)
    last = [-1] * 256
    for j in range(m):
        last[ord(P[j])] = j
    return last


def compute_good_suffix(P):
    m = len(P)
    suffix, default = [0] * m, [0] * m
    suffix[m - 1] = m
    j, k = m - 2, m - 1
    while j >= 0:
        if j > k and suffix[m - 1 - j + k] < j - k:
            suffix[j] = suffix[m - 1 - j + k]
        else:
            if j < k:
                k = j
            while k >= 0 and P[k] == P[m - 1 - j + k]:
                k -= 1
            suffix[j] = j - k
        j -= 1
    return suffix


def search(T, P):
    n, m = len(T), len(P)
    last = compute_bad_char(P)
    suffix = compute_good_suffix(P)
    i = 0
    while i <= n - m:
        j = m - 1
        while j >= 0 and T[i+j] == P[j]:
            j -= 1
        if j < 0:
            return i
        x = j - last[ord(T[i+j])]
        y = suffix[j]
        i += max(x, y)
    return -1
总结

字符串搜索是一道经典的算法问题,多种算法都可以解决这个问题。Brute-Force 算法是最简单的算法,但是时间复杂度比较高;KMP 算法通过预处理来跳过无需比较的字符,时间复杂度较低;Boyer-Moore 算法则通过两个规则来跳过文本串中的无需匹配的字符,时间复杂度最低。因此,在实际应用中,需要根据特定的问题选择合适的算法来解决。