📅  最后修改于: 2023-12-03 15:28:36.007000             🧑  作者: Mango
重复子序列是指在一个字符串中,长度至少为2的两个子串在原字符串中出现了多次。
例如,字符串“ABABC”中,“AB”是一个重复子序列,在位置1和位置3分别出现了一次。另一个重复子序列为“AA”,在位置1和位置2分别出现了一次。需要注意的是,“A”虽然在字符串中出现了多次,但是它并不是一个重复子序列,因为它的长度为1。
我们可以使用哈希表来判断字符串中是否存在重复子序列。对于每一个长度大于等于2的连续子串,在哈希表中记录其出现的起始位置。当我们扫描到一个新的子串时,首先计算它的哈希值,然后检查哈希表中是否已经存在该哈希值。如果存在,说明该子串曾经出现过,那么我们就可以找到它和当前子串的起始位置,从而判断它们是否完全相同。
代码实现如下所示:
def find_repeated_substring(s: str) -> str:
n = len(s)
hash_map = {}
for i in range(2, n + 1):
for j in range(n - i + 1):
sub_str = s[j:j + i]
hash_value = hash(sub_str)
if hash_value in hash_map and hash_map[hash_value] != j:
return sub_str
hash_map[hash_value] = j
return ""
注意,在哈希表中我们需要记录子串出现的起始位置,因为存在相同的哈希值对应多个不同的子串。
如果我们需要找到字符串中所有的重复子序列,可以使用字符串算法中的后缀数组和公共前缀数组。
后缀数组的定义是:给定一个字符串S,将S的所有后缀按字典序排序后所得到的数组。例如,字符串“abcd”的后缀数组为[‘abcd’, ‘bcd’, ‘cd’, ‘d’]。
公共前缀数组的定义是:给定一个字符串S和它的后缀数组suffix,令LCP[i]表示suffix[i]和suffix[i-1]的最长公共前缀的长度。
假设我们已经得到了字符串的后缀数组和公共前缀数组,那么我们可以依次遍历后缀数组中的每一个后缀,找到它和前一个后缀的最长公共前缀。如果它们的最长公共前缀长度大于等于2,那么它们就是一个重复子序列。
注意,如果后缀数组中有重复的后缀,那么它们对应的公共前缀数组中的值也会是重复的。因此,我们需要去重处理,只保留其中一个。
代码实现如下所示:
def find_all_repeated_substrings(s: str) -> List[str]:
n = len(s)
suffix_array = sorted(range(n), key=lambda i: s[i:])
LCP = [0] * n
for i in range(1, n):
LCP[suffix_array[i]] = lcp(s, suffix_array[i-1], suffix_array[i])
res = set()
for i in range(1, n):
if LCP[i] >= 2:
res.add(s[suffix_array[i]: suffix_array[i] + LCP[i]])
return list(res)
def lcp(s: str, i: int, j: int) -> int:
n = len(s)
k = 0
while i < n and j < n and s[i] == s[j]:
i += 1
j += 1
k += 1
return k
注意,这里使用了Python内置的set来进行去重处理,因此返回的结果是一个列表,而不是一个集合。此外,我们还需要实现一个lcp函数来计算任意两个后缀的最长公共前缀长度。