📌  相关文章
📜  没有两个相邻字母相同的元音的最长子串(1)

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

没有两个相邻字母相同的元音的最长子串

介绍

这是一个可以找出没有两个相邻字母相同的元音的最长子串的算法。元音字母是指英语中的 a、e、i、o、u 这五个字母。该算法使用了动态规划的思想,时间复杂度为 O(n),空间复杂度为 O(n),效率较高。

算法思路
  1. 定义两个数组:dppredp[i] 表示以第 i 个字母结尾的最长子串长度,并且第 i 个字母为元音字母;pre[i] 表示以第 i 个字母结尾的最长子串的上一个元音字母的下标。
  2. 遍历整个字符串,对于每个位置 i: a. 如果第 i 个字母不是元音字母,那么 dp[i]pre[i] 均为 0; b. 如果第 i 个字母是元音字母,则: i. 如果前面没有元音字母,那么 dp[i] = 1pre[i] = -1; ii. 如果前面有元音字母,那么 dp[i] = dp[i-1] + 1pre[i] = j,其中 j 是前面最近的一个元音字母的下标。
  3. 遍历完整个字符串后,找出 dp 数组中的最大值,即为没有两个相邻字母相同的元音的最长子串的长度。通过 pre 数组可以还原出该子串。
代码实现
def longest_substring(s: str) -> str:
    vowels = {'a', 'e', 'i', 'o', 'u'}
    dp = [0] * len(s)  # dp[i] 表示以第 i 个字母结尾的最长子串长度,并且第 i 个字母为元音字母
    pre = [-1] * len(s)  # pre[i] 表示以第 i 个字母结尾的最长子串的上一个元音字母的下标
    max_len = 0  # 最长子串的长度
    end = 0  # 最长子串的结尾位置
    for i in range(len(s)):
        if s[i] not in vowels:
            dp[i], pre[i] = 0, -1
        else:
            if i == 0:  # 特殊处理第一个元音字母
                dp[i], pre[i] = 1, -1
            else:
                if s[i - 1] in vowels:  # 检查前面是否有元音字母
                    pre[i] = pre[i - 1]
                else:
                    pre[i] = i - 1
                dp[i] = i - pre[i]
        if dp[i] > max_len:
            max_len, end = dp[i], i
    start = end - max_len + 1  # 最长子串的起始位置
    return s[start:end+1]
测试用例
assert longest_substring('leetcode') == 'od'
assert longest_substring('abcdeaicduo') == 'aecduo'