📌  相关文章
📜  字符串匹配,其中一个字符串包含字符(1)

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

字符串匹配

在编程中,字符串匹配是经常会涉及到的问题。其中一个常见的应用场景是找出一个字符串中是否含有另一个字符串(其中一个字符串作为主题),如果有则返回主题字符串所在的位置或者数量。

常见的字符串匹配算法有暴力匹配、KMP算法、Boyer-Moore算法、Sunday算法等。

暴力匹配

暴力匹配是最基础也是最简单的字符串匹配算法,它的思路就是从主题字符串的第一个字符开始和目标字符串的第一个字符开始逐一比较,如果不同,则主题字符串从下一个字符开始与目标字符串的第一个字符重新比较,直到找到匹配或者主题字符串的所有字符都被比较完为止。

暴力匹配算法的时间复杂度为O(nm),其中n为主题字符串的长度,m为目标字符串的长度。当主题字符串和目标字符串大小相同时,暴力匹配的效率最高。

以下是暴力匹配算法的Python代码实现:

def violent_match(s, p):
    n = len(s)
    m = len(p)
    i = 0  # 主串的指针
    j = 0  # 模式串的指针
    while i < n and j < m:
        if s[i] == p[j]:
            # 如果当前字符匹配成功,那么主串和模式串的指针都加1
            i += 1
            j += 1
        else:
            # 如果失配,主串指针后退到前面的位置,模式串的指针归0
            i = i - j + 1
            j = 0
    if j == m:
        return i - j
    else:
        return -1
KMP算法

KMP算法(Knuth-Morris-Pratt algorithm)是一种高效的字符串匹配算法,它利用模式串中已经匹配过的内容,尽可能地减少主串与模式串的比较次数,从而使得匹配的效率得到提高。KMP算法的时间复杂度为O(m+n),其中n为主题字符串的长度,m为目标字符串的长度。

以下是KMP算法的Python代码实现:

def get_next(p):
    m = len(p)
    next = [0] * m
    j = 0
    for i in range(1, m):
        while j > 0 and p[i] != p[j]:
            j = next[j - 1]
        if p[i] == p[j]:
            j += 1
        next[i] = j
    return next


def kmp_match(s, p):
    n = len(s)
    m = len(p)
    next = get_next(p)
    i = 0  # 主串的指针
    j = 0  # 模式串的指针
    while i < n and j < m:
        if s[i] == p[j]:
            i += 1
            j += 1
        elif j > 0:
            j = next[j - 1]
        else:
            i += 1
    if j == m:
        return i - j
    else:
        return -1
Boyer-Moore算法

Boyer-Moore算法是一种高效的字符串匹配算法,它是从右往左匹配,采用“坏字符规则”和“好后缀规则”来进行匹配。Boyer-Moore算法的时间复杂度为O(m+n),其中n为主题字符串的长度,m为目标字符串的长度。

以下是Boyer-Moore算法的Python代码实现:

def get_bad_char(p):
    m = len(p)
    bad_char = [-1] * 256
    for i in range(m):
        bad_char[ord(p[i])] = i
    return bad_char


def get_good_suffix(p):
    m = len(p)
    suffix = [0] * m
    good_suffix = [0] * m
    suffix[m - 1] = m
    j = m - 1
    for i in range(m - 2, -1, -1):
        if i > j and suffix[i + m - 1 - k] < i - j:
            suffix[i] = suffix[i + m - 1 - k]
        else:
            if i < j:
                j = i
            k = i
            while j >= 0 and p[j] == p[j + m - 1 - k]:
                j -= 1
            suffix[i] = k - j
    for i in range(m):
        good_suffix[i] = m
    j = 0
    for i in range(m - 1, -1, -1):
        if suffix[i] == i + 1:
            while j < m - 1 - i:
                if good_suffix[j] == m:
                    good_suffix[j] = m - 1 - i
                j += 1
    for i in range(m - 1):
        good_suffix[m - 1 - suffix[i]] = m - 1 - i
    return good_suffix


def bm_match(s, p):
    n = len(s)
    m = len(p)
    bad_char = get_bad_char(p)
    good_suffix = get_good_suffix(p)
    i = m - 1  # pattern的指针
    j = m - 1  # text的指针
    while i >= 0 and j >= 0:
        if s[j] == p[i]:
            i -= 1
            j -= 1
        else:
            x = bad_char[ord(s[j])]
            y = j - i
            if x >= 0:
                i = max(good_suffix[i], x - y)
            else:
                i = good_suffix[i]
            j = j + m - min(i + 1, 1 + bad_char[ord(s[j - 1])])
    if i < 0:
        return j + 1
    else:
        return -1
Sunday算法

Sunday算法是一种字符串匹配算法,它是从左往右匹配,每次根据主串中的字符以及模式串的后缀字符来确定匹配位置。Sunday算法的时间复杂度为O(mn),其中n为主题字符串的长度,m为目标字符串的长度。

以下是Sunday算法的Python代码实现:

def sunday_match(s, p):
    n = len(s)
    m = len(p)
    i = 0  # 主串的指针
    j = 0  # 模式串的指针
    while i < n and j < m:
        if s[i] == p[j]:
            i += 1
            j += 1
        else:
            if i + m - j < n and s[i + m - j] in p:
                i = i + m - j - p[::-1].index(s[i + m - j])
            else:
                i = i + m - j + 1
            j = 0
    if j == m:
        return i - j
    else:
        return -1