Medium
题目描述
给你一个字符串 word 和一个非负整数 k。
返回 word 的子串中包含每个元音字母(‘a’, ’e’, ‘i’, ‘o’, ‘u’)至少一次且恰好包含 k 个辅音字母的子串总数。
示例 1:
输入:word = "aeioqq", k = 1
输出:0
解释:没有包含所有元音字母的子串。
示例 2:
输入:word = "aeiou", k = 0
输出:1
解释:唯一包含所有元音字母且零个辅音字母的子串是 word[0..4],即 "aeiou"。
示例 3:
输入:word = "ieaouqqieaouqq", k = 1
输出:3
解释:包含所有元音字母和一个辅音字母的子串有:
- word[0..5],即 "ieaouq"
- word[6..11],即 "qieaou"
- word[7..12],即 "ieaouq"
约束条件:
5 <= word.length <= 250word仅由小写英文字母组成0 <= k <= word.length - 5
提示:
- 使用哈希表并检查所有子串。
解题思路
这道题需要找到包含所有5个元音字母至少一次且恰好包含k个辅音字母的子串数量。
解题思路
方法一:暴力枚举(推荐) 由于字符串长度较小(≤250),我们可以枚举所有可能的子串,对每个子串检查是否满足条件:
- 包含所有5个元音字母(a,e,i,o,u)至少一次
- 恰好包含k个辅音字母
具体实现:
- 使用双重循环枚举所有子串的起始和结束位置
- 对每个子串维护元音字母计数和辅音字母计数
- 检查是否所有元音字母都出现过且辅音字母数量恰好为k
方法二:滑动窗口优化 虽然可以考虑滑动窗口,但由于需要同时满足"包含所有元音"和"恰好k个辅音"两个条件,窗口的伸缩逻辑较为复杂,在数据规模较小的情况下,暴力解法更加直观易懂。
时间复杂度分析:由于字符串长度最大为250,O(n²)的复杂度是可以接受的。
代码实现
class Solution {
public:
int countOfSubstrings(string word, int k) {
int n = word.length();
int count = 0;
for (int i = 0; i < n; i++) {
unordered_set<char> vowels;
int consonants = 0;
for (int j = i; j < n; j++) {
char c = word[j];
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
vowels.insert(c);
} else {
consonants++;
}
// 如果辅音字母数超过k,后续子串都不可能满足条件
if (consonants > k) break;
// 检查是否满足条件
if (vowels.size() == 5 && consonants == k) {
count++;
}
}
}
return count;
}
};
class Solution:
def countOfSubstrings(self, word: str, k: int) -> int:
n = len(word)
count = 0
for i in range(n):
vowels = set()
consonants = 0
for j in range(i, n):
c = word[j]
if c in 'aeiou':
vowels.add(c)
else:
consonants += 1
# 如果辅音字母数超过k,后续子串都不可能满足条件
if consonants > k:
break
# 检查是否满足条件
if len(vowels) == 5 and consonants == k:
count += 1
return count
public class Solution {
public int CountOfSubstrings(string word, int k) {
int n = word.Length;
int count = 0;
for (int i = 0; i < n; i++) {
HashSet<char> vowels = new HashSet<char>();
int consonants = 0;
for (int j = i; j < n; j++) {
char c = word[j];
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
vowels.Add(c);
} else {
consonants++;
}
// 如果辅音字母数超过k,后续子串都不可能满足条件
if (consonants > k) break;
// 检查是否满足条件
if (vowels.Count == 5 && consonants == k) {
count++;
}
}
}
return count;
}
}
var countOfSubstrings = function(word, k) {
const vowels = new Set(['a', 'e', 'i', 'o', 'u']);
let count = 0;
for (let i = 0; i < word.length; i++) {
let vowelSet = new Set();
let consonants = 0;
for (let j = i; j < word.length; j++) {
if (vowels.has(word[j])) {
vowelSet.add(word[j]);
} else {
consonants++;
}
if (vowelSet.size === 5 && consonants === k) {
count++;
}
if (consonants > k) {
break;
}
}
}
return count;
};
复杂度分析
| 复杂度类型 | 复杂度 |
|---|---|
| 时间复杂度 | O(n²) |
| 空间复杂度 | O(1) |
其中 n 为字符串长度。时间复杂度为 O(n²),因为需要枚举所有可能的子串;空间复杂度为 O(1),只使用了常数额外空间(哈希集合最多存储5个元音字母)。