统计所有子字符串中元音的总数 — 高效解法详解
题目描述
给定一个字符串 word,返回它所有 子字符串 中 元音 的总数。
元音指的是 'a'、'e'、'i'、'o' 和 'u'。
- 子字符串 指的是字符串中连续的非空字符序列。
- 输入字符串由小写英文字母组成,长度范围为
1 <= word.length <= 10^5。 - 由于答案可能超过 32 位整数范围,需要用更大的数据类型处理。
示例说明
示例 1
输入:word = "aba"
所有子字符串有:
"a", "ab", "aba", "b", "ba", "a"
计算每个子字符串中元音数量:
"a"→ 1 个元音"ab"→ 1 个元音"aba"→ 2 个元音"b"→ 0 个元音"ba"→ 1 个元音"a"→ 1 个元音
元音总数 = 1 + 1 + 2 + 0 + 1 + 1 = 6
示例 2
输入:word = "abc"
子字符串:
"a", "ab", "abc", "b", "bc", "c"
元音数:
"a"→ 1"ab"→ 1"abc"→ 1"b"→ 0"bc"→ 0"c"→ 0
总和 = 3
示例 3
输入:word = "ltcd"
所有子字符串均不含元音,因此总和为 0。
示例 4
输入:word = "noosabasboosa"
输出:237 (题目给出的正确结果)
解题分析
直接枚举所有子字符串,计算每个子字符串内元音数的方法,时间复杂度约为 O(n²)(字符串长度 n 最高可达 10^5),显然不可行。
因此,我们需要寻找更高效的方法。
关键思路
- 注意到每个元音字符对结果的贡献是独立的。
- 具体来说,对于字符串长度为 n 的字符串中,假设第 i 个字符是元音。
- 这个字符能够被多少个子字符串包含呢?
举例说明:
字符串索引从 0 开始,到 n-1。
- 子字符串的起点可以从
[0 ... i]选择,共有i + 1种选择。 - 子字符串的终点可以从
[i ... n - 1]选择,共有n - i种选择。
因此,包含索引 i 处字符的子字符串总数是:
(i + 1) * (n - i)
因为这个字符是元音,它在所有包含它的子字符串中都会贡献 1 个元音。所以元音总数的贡献就是这个数。
解题方法
将字符串中所有元音字符的位置分别计算贡献,并累加。
代码实现(Python)
class Solution:
def countVowels(self, word: str) -> int:
vowels = set('aeiou')
n = len(word)
total = 0
for i, ch in enumerate(word):
if ch in vowels:
total += (i + 1) * (n - i)
return total
复杂度分析
- 时间复杂度:O(n),只遍历一次字符串即可。
- 空间复杂度:O(1),只使用了常数额外空间。
示例再验证
以示例 "aba" 为例:
- i=0,字符
'a',贡献(0+1)*(3-0) = 1*3 = 3 - i=1,字符
'b',非元音,贡献 0 - i=2,字符
'a',贡献(2+1)*(3-2) = 3*1 = 3
总贡献 = 3 + 0 + 3 = 6,与示例答案一致。
方法优劣对比
| 方法 | 时间复杂度 | 是否可行(n=10^5) | 说明 |
|---|---|---|---|
| 枚举所有子串计数 | O(n²) | 不可行 | 子串数量达 O(n²),超时严重。 |
| 按元音贡献计算 | O(n) | 可行 | 只遍历一次字符串,效率极高。 |
总结
- 该问题的核心是理解每个元音字符在所有子串中的出现次数。
- 利用数学推导避免暴力枚举,使问题复杂度从 O(n²) 降至 O(n)。
- 该思路也适合解决类似“字符贡献总和”的题目。
393

被折叠的 条评论
为什么被折叠?



