统计范围内的元音字符串数目-LeetCode
2559. 统计范围内的元音字符串数目
🎯 问题描述
描述:
给你一个下标从 0 开始的字符串数组 words 和一个二维整数数组 queries。
对于每个查询 queries[i] = [li, ri],请计算 words 中下标在 [li, ri] 范围内(包含两端)有多少个元音字符串。
元音字符串定义:
- 该字符串以元音字母开头 并且 以元音字母结尾。
- 元音字母包括:‘a’, ‘e’, ‘i’, ‘o’, ‘u’。
说明:
-
这是一个前缀和的经典应用场景。
-
核心策略:
- 题目涉及多次区间求和查询。
- 如果直接对每个查询遍历区间,时间复杂度为 ,在数据量大时会超时。
- 利用前缀和数组,我们可以先预处理出每个位置之前有多少个元音字符串。
- 查询时,利用前缀和的差值在 时间内得到结果。
-
示例:
-
示例 1:
1 | 输入:words = ["aba","bcb","ece","aa","e"], queries = [[0,2],[1,4],[1,1]] |
💻 解题思路
思路1:前缀和 + 预处理
核心逻辑
- 预处理标记:
- 遍历
words数组。 - 对于每个单词,检查首字符和尾字符是否都在 “aeiou” 中。
- 如果是,标记为 1;否则标记为 0。
- 遍历
- 构建前缀和数组
pre:pre[i+1]表示words[0]到words[i]中元音字符串的总数量。- 递推公式:
pre[i+1] = pre[i] + flag。 - 注意
pre数组长度为n+1,且pre[0] = 0,这样可以方便处理边界情况。
- 处理查询:
- 对于每个查询
[l, r],利用前缀和性质计算区间和。 - 结果 =
pre[r+1] - pre[l]。 - 这表示前
r+1个单词的总数减去前l个单词的总数,剩下的就是区间[l, r]内的数量。
- 对于每个查询
代码实现
1 | class Solution: |
📊 性能分析
- 时间复杂度:
- 构建前缀和数组:,其中 是
words的长度。判断每个字符串首尾字符耗时 。 - 处理查询:,其中 是
queries的长度。每个查询只需 时间进行减法运算。 - 总体线性时间,非常高效。
- 构建前缀和数组:,其中 是
- 空间复杂度:
- 需要一个长度为 的
pre数组来存储前缀和。 - 结果数组
ans占用 空间(通常不计入额外空间复杂度,因为是返回值)。
- 需要一个长度为 的
思考
-
前缀和的定义技巧:
- 我们定义
pre[i+1]为前i+1个元素(下标 0 到 i)的满足条件的数量。 - 这种定义方式(
pre长度比原数组多 1,且pre[0]=0)是处理区间查询的标准技巧。 - 它避免了处理
l=0时的边界特判,因为pre[0]天然为 0。
- 我们定义
-
为什么使用前缀和?
- 如果不使用前缀和,对于每个查询
[l, r],我们需要遍历words[l]到words[r],耗时 。 - 在最坏情况下(查询区间很大且查询次数多),总时间复杂度接近 。
- 前缀和通过一次 的预处理,将每次查询降为 ,极大地提高了效率。
- 如果不使用前缀和,对于每个查询
-
元音判断优化:
- 代码中使用
s[0] in "aeiou"。在 Python 中,对于短字符串,这种查找是很快的。 - 如果需要极致优化,可以将 “aeiou” 转换为集合
set('aeiou'),查找时间复杂度稳定为 。
- 代码中使用
-
空间优化:
- 如果输入数组
words允许修改,或者我们不需要保留原始数据,其实可以用words数组本身来存储前缀和(如果类型允许)。 - 但在本题中,为了代码清晰和安全性,开辟新的
pre数组是最佳选择。
- 如果输入数组
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!






