所有元音按顺序排布的最长子字符串

标签: 字符串 滑动窗口

难度: Medium

当一个字符串满足如下条件时,我们称它是 美丽的 :

  • 所有 5 个英文元音字母('a' ,'e' ,'i' ,'o' ,'u')都必须 至少 出现一次。
  • 这些元音字母的顺序都必须按照 字典序 升序排布(也就是说所有的 'a' 都在 'e' 前面,所有的 'e' 都在 'i' 前面,以此类推)

比方说,字符串 "aeiou" 和 "aaaaaaeiiiioou" 都是 美丽的 ,但是 "uaeio" ,"aeoiu" 和 "aaaeeeooo" 不是美丽的 。

给你一个只包含英文元音字母的字符串 word ,请你返回 word最长美丽子字符串的长度 。如果不存在这样的子字符串,请返回 0 。

子字符串 是字符串中一个连续的字符序列。

 

示例 1:

输入:word = "aeiaaioaaaaeiiiiouuuooaauuaeiu"
输出:13
解释:最长子字符串是 "aaaaeiiiiouuu" ,长度为 13 。

示例 2:

输入:word = "aeeeiiiioooauuuaeiou"
输出:5
解释:最长子字符串是 "aeiou" ,长度为 5 。

示例 3:

输入:word = "a"
输出:0
解释:没有美丽子字符串,所以返回 0 。

 

提示:

  • 1 <= word.length <= 5 * 105
  • word 只包含字符 'a''e''i''o' 和 'u' 。

Submission

运行时间: 124 ms

内存: 24.0 MB

class Solution:
    def longestBeautifulSubstring(self, word: str) -> int:
        ch_str = ''.join([k for k, g in groupby(word)])
        g_list = [list(g) for k, g in groupby(word)]

        num = ch_str.count('aeiou')
        if num == 0:
            return 0
        res = 0
        ind = 0
        for i in range(num):
            if i == 0:
                ind = ch_str.find('aeiou', ind)
            else:
                ind = ch_str.find('aeiou', ind + 5)
            res = max(res, sum([len(g_list[ind + i]) for i in range(5)]))

        return res

Explain

此题解采用了两个关键步骤来找到最长的美丽子字符串。首先,使用groupby函数从itertools库来聚合连续相同的字符,从而便于后续处理。第二步,将原字符串中连续相同的字符压缩成一个字符形成新的字符串ch_str,并将每组字符的长度存入列表g_list。然后,此解法通过在ch_str中找到'aeiou'这一特定模式的所有出现位置,并计算出从每个位置开始的连续五组字符的总长度,这样可以确保找到的子字符串符合美丽字符串的要求。最后,比较所有符合条件的子字符串长度,返回最长的一个。

时间复杂度: O(n)

空间复杂度: O(n)

class Solution:
    def longestBeautifulSubstring(self, word: str) -> int:
        # 使用groupby压缩连续相同的字符并创建ch_str
        ch_str = ''.join([k for k, g in groupby(word)])
        # 创建g_list存储每组字符的长度
        g_list = [list(g) for k, g in groupby(word)]

        # 计算ch_str中'aeiou'模式出现的次数
        num = ch_str.count('aeiou')
        if num == 0:
            return 0
        res = 0
        ind = 0
        for i in range(num):
            if i == 0:
                ind = ch_str.find('aeiou', ind)
            else:
                ind = ch_str.find('aeiou', ind + 5)
            # 计算从ind开始的五个组合字符的总长度并更新结果
            res = max(res, sum([len(g_list[ind + i]) for i in range(5)]))

        return res

Explore

使用groupby聚合连续相同的字符可以简化字符串的结构,将连续相同的字符视为一个整体。这样做有助于减少后续处理的复杂度,因为在寻找特定模式(如'aeiou')时,我们可以忽略单个字符的重复,只关注字符种类的变化,从而更加直观和高效地判断模式的出现。

将连续相同的字符压缩成一个字符主要是为了更容易地识别和处理连续的不同字符序列,特别是对于本题要求的'aeiou'顺序排列的子字符串。这种压缩使得在ch_str中直接用字符串查找函数(如find)就能快速定位到这一模式,从而简化了代码逻辑,提高了算法效率。对于最长美丽子字符串的寻找,这样的处理允许我们直接根据模式匹配的位置,快速计算出原字符串中相应部分的长度。

题解中通过计算ch_str中'aeiou'模式的出现确实可以找到所有可能的美丽子字符串的起始位置,但这种方法本身不能保证每个找到的'aeiou'之后还有足够的字符来构成完整的子字符串。因此,还需要额外的逻辑来验证每个模式后是否有足够的字符组成完整的美丽子字符串,这通常涉及到边界条件的检查。

在处理边界情况时,首先需要检查'aeiou'模式后是否还有足够的字符组存在。如果'aeiou'模式出现在字符串末尾或后续字符组不足五个,则这种情况下的'aeiou'模式不能构成有效的美丽子字符串。解决方法是在遍历ch_str时,每次找到'aeiou'后,检查后续是否还有足够的字符组(至少四个),只有在满足这个条件时,才计算这五个字符组的总长度。这种检查确保了每次计算的都是有效且完整的美丽子字符串。