📌  相关文章
📜  最长的子串,使得没有三个连续字符相同(1)

📅  最后修改于: 2023-12-03 14:55:23.310000             🧑  作者: Mango

最长的子串,使得没有三个连续字符相同

这里我们介绍一种算法,可以找到一个字符串中最长的子串,使得没有三个连续字符相同。该算法的时间复杂度为 $O(n)$。

算法

我们首先需要找出一个长度为3的子串,而这个子串中的字符都是不同的,否则无论怎样都不能满足“没有三个连续字符相同”的条件。

接下来我们从这个长度为3的子串开始,每次往后移动一个字符,如果新加入的字符会让字符串中出现三个连续相同的字符,那么我们就需要将子串的起始位置向后移动一个字符。

具体来说,假设我们已经找到了一个长度为 $k$ 的子串 $s_{i-k+1}, s_{i-k+2}, \dots, s_i$,且这个子串没有三个连续字符相同。现在我们需要确定下一个字符,也就是 $s_{i+1}$。如果 $s_i$ 和 $s_{i-1}$ 相同,那么我们只能选择另外一种字符,否则我们可以选择和 $s_i$ 相同的字符。

如果新加入的字符 $s_{i+1}$ 会导致 $s_{i-k+2}, s_{i-k+3}, \dots, s_{i+1}$ 这 $k$ 个字符中出现三个连续相同的字符,那么我们就需要把子串的起始位置向后移动一位,也就是从 $s_{i-k+2}$ 开始重新构造一个长度为 $k$ 的、没有三个连续相同字符的子串,然后再从 $s_{i+2}$ 开始继续确定下一个字符。

为了方便起见,我们可以维护两个指针 $l$ 和 $r$,表示当前子串的起始和终止位置。每次确定下一个字符时,我们只需要判断是否需要将 $l$ 向右移动一位,然后将 $r$ 向右移动一位即可。

代码

以下是 Python 代码实现:

def longest_substring(s: str) -> str:
    n = len(s)
    if n < 3:
        return s
    l = r = 0  # 当前子串的起始和终止位置
    max_len = 2  # 最长子串的长度
    for i in range(2, n):
        if s[i] == s[i-1] and s[i-1] == s[i-2]:
            l = i-1
        if i-r+1 > max_len:
            max_len = i-r+1
            res = s[l:r+1]
        if i-r+1 < 3:
            r = i
        elif i-r+1 == 3:
            if s[i] != s[i-1]:
                r = i
            else:
                l = i-1
                r = i
        else:
            if s[i] != s[i-1]:
                r = i
            else:
                l = i-1
                r = i-2
    return res if max_len >= 3 else s[:3]

该算法的时间复杂度为 $O(n)$,因为我们只遍历了一遍原字符串,对于每个字符只进行了常数次操作。