📌  相关文章
📜  找到最长的子字符串,它是前缀、后缀并且也出现在字符串中 |设置 2(1)

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

找到最长的子字符串,它是前缀、后缀并且也出现在字符串中
问题描述

给定一个字符串,找到其中最长的子字符串,使得该子字符串既是该字符串的前缀,也是该字符串的后缀,并且在该字符串中出现过。

例如,对于字符串 "abcabcabc",最长的子字符串是 "abc",因为它同时是该字符串的前缀、后缀,并且在该字符串中出现过。

解决方案

暴力解法

最简单的解决方案是暴力枚举所有可能的子字符串,并判断它是否同时是前缀、后缀并且出现在原字符串中。

# python

def longest_prefix_suffix(string):
    n = len(string)
    longest_str = ""
    for i in range(n):
        for j in range(i, n):
            substr = string[i:j+1]
            if substr != string and substr == string[:j-i+1] and substr == string[n-j-1:]:
                    longest_str = substr
    return longest_str

这种方法的时间复杂度为 $O(N^3)$,其中 $N$ 表示字符串的长度。时间复杂度过高,在实际应用中一般不采用。

KMP算法

更高效的解决方案是使用 KMP 算法,在线性时间内完成匹配。

KMP 算法常用于字符串匹配问题,其核心思想是构建一个部分匹配表(partial match table),用于快速判断字符串是否匹配。该表记录了每个字符串前缀的最长的相等的真前缀和真后缀长度(真前缀指不包含整个字符串,真后缀指除去整个字符串)。

对于样例 "abcabcabc",它的部分匹配表如下所示:

| 字符串 | 最长真前缀和后缀相等的长度 | | ----- | --------------------------- | | a | 0 | | ab | 0 | | abc | 0 | | abca | 1 | | abcab | 2 | | abcabc| 3 | | abcabca| 1 | | abcabcab| 2 | | abcabcabc| 3 |

在 KMP 算法中,需要先求出给定字符串的部分匹配表,然后遍历该表,找到诸如 kmp_table[j] == kmp_table[kmp_table[j]] ($j$ 为 $i$ 的因子)的元素,这些元素表示存在一个长度为 $kmp_table[j]$ 的子序列既是前缀又是后缀。需要注意的是,因为真前缀和真后缀不能包括整个字符串,因此要将整个字符串去掉。

最长子字符串的长度即为最后一个元素的值。

# python

def longest_prefix_suffix(string):
    n = len(string)
    kmp_table = [0] * n
    # 构建部分匹配表
    i, j = 1, 0
    while i < n:
        if string[i] == string[j]:
            j += 1
            kmp_table[i] = j
            i += 1
        elif j > 0:
            j = kmp_table[j-1]  # 回溯
        else:
            i += 1
    # 在部分匹配表中寻找最长子字符串
    longest_substring_len = kmp_table[-1]
    while longest_substring_len > 0:
        substring = string[:longest_substring_len]
        if string.count(substring) >= 2:
            return substring
        longest_substring_len = kmp_table[longest_substring_len-1]
    return ""

这种方法的时间复杂度为 $O(N)$,其中 $N$ 表示字符串的长度。由于 KMP 算法的实现比较麻烦,因此在面试中可能不会要求实现 KMP 算法,但是了解 KMP 算法的基本思想对于解决字符串匹配问题非常有用。

总结

本文介绍了如何寻找一个字符串中最长的既是前缀、后缀又在字符串中出现过的子字符串。暴力枚举的时间复杂度较高,不适用于实际应用。KMP 算法能够在线性时间内完成匹配,但实现较为困难。在面试中可能不会要求实现 KMP 算法,但是了解 KMP 算法的基本思想对于解决字符串匹配问题非常有用。