返回
创建于
状态公开

详细的例子和推理来解释「所有子字符串中的元音」这道题的高效做法。

问题本质

给定一个字符串 word,你需要返回所有子字符串中元音('a', 'e', 'i', 'o', 'u')出现的总次数。
注意:不是统计不同子串的元音数,而是所有子串中元音出现的总和,即每个元音在所有包含它的子串中都要计数。

直观但低效的做法

最直接的思路是:

  • 枚举所有子串
  • 对每个子串统计元音数并累加

但这样复杂度是 O(n3)O(n^3)(枚举子串 O(n2)O(n^2),每个子串统计元音 O(n)O(n)),对于长字符串会超时。

高效做法的核心思想

每个元音在所有包含它的子串中会被重复计数多次。我们可以直接计算每个元音在多少个子串中出现,然后累加。

数学推导

假设字符串长度为 nn,元音出现在下标 ii(从0开始)。

  • ii 结尾的子串有 i+1i+1 个(起点可以是0到i)
  • ii 为起点的子串有 nin-i 个(终点可以是i到n-1)

所以包含下标 ii 的所有子串数量是 (i+1)×(ni)(i+1) \times (n-i)

举例说明:

假设字符串是 "abcde",长度为5。

  • 下标0的字符'a',出现在 (0+1)×(50)=5(0+1) \times (5-0) = 5 个子串里
  • 下标4的字符'e',出现在 (4+1)×(54)=5(4+1) \times (5-4) = 5 个子串里

实现步骤

  1. 初始化总数为0。
  2. 遍历字符串的每个字符及其下标。
  3. 如果是元音,计算它的贡献 (i+1)×(ni)(i+1) \times (n-i) 并加到总数上。
  4. 遍历结束后返回总数。

代码(Go语言)

go
1func countVowels(word string) int64 {
2    n := len(word)
3    var total int64 = 0
4    vowels := map[byte]bool{'a': true, 'e': true, 'i': true, 'o': true, 'u': true}
5    for i := 0; i < n; i++ {
6        if vowels[word[i]] {
7            total += int64(i+1) * int64(n-i)
8        }
9    }
10    return total
11}

例子详细推演

word = "aba" 为例:

  • 长度 n = 3
  • 下标0: 'a',是元音,贡献 = (0+1)*(3-0)=3
  • 下标1: 'b',不是元音,贡献=0
  • 下标2: 'a',是元音,贡献 = (2+1)*(3-2)=3

总和 = 3 + 0 + 3 = 6

所有子串及元音数如下:

  • "a":1
  • "ab":1
  • "aba":2
  • "b":0
  • "ba":1
  • "a":1 总和 = 1+1+2+0+1+1 = 6

和公式计算一致。

总结

  • 每个元音出现的次数 = (下标+1) * (总长-下标)
  • 只需遍历一次字符串,时间复杂度 O(n),空间 O(1)
  • 适合大数据量场景