其他系列文章导航
文章目录
[2.1 方法一:滑动窗口](#2.1 方法一:滑动窗口)
[2.2 方法二:滑动窗口优化版](#2.2 方法二:滑动窗口优化版)
[3.1 方法一:滑动窗口](#3.1 方法一:滑动窗口)
[3.2 方法二:滑动窗口优化版](#3.2 方法二:滑动窗口优化版)
[4.1 方法一:滑动窗口](#4.1 方法一:滑动窗口)
[4.2 方法二:滑动窗口优化版](#4.2 方法二:滑动窗口优化版)
前言
这是力扣的 1456 题,难度为中等,解题方案有很多种,本文讲解我认为最奇妙的一种。
又是一道滑动窗口的典型例题,可以帮助我们巩固滑动窗口算法。
一、题目描述
给你字符串 s
和整数 k
。
请返回字符串 s
中长度为 k
的单个子字符串中可能包含的最大元音字母数。
英文中的 元音字母 为(a
, e
, i
, o
, u
)。
示例 1:
输入:s = "abciiidef", k = 3 输出:3 解释:子字符串 "iii" 包含 3 个元音字母。
示例 2:
输入:s = "aeiou", k = 2 输出:2 解释:任意长度为 2 的子字符串都包含 2 个元音字母。
示例 3:
输入:s = "leetcode", k = 3 输出:2 解释:"lee"、"eet" 和 "ode" 都包含 2 个元音字母。
示例 4:
输入:s = "rhythms", k = 4 输出:0 解释:字符串 s 中不含任何元音字母。
示例 5:
输入:s = "tryhard", k = 4 输出:1
提示:
1 <= s.length <= 10^5
s
由小写英文字母组成1 <= k <= s.length
二、题解
2.1 方法一:滑动窗口
思路与算法:
首先定义一个 list 来存放元音字母,可以用 list 自带的 api :contains 来判断是否包含。
还需要定义两个变量:
- 当前元音数量。
- 最大元音数量。
然后设置初始窗口,那我们就在数组最前方取 k 个元素当作窗口。
记录下初始窗口的元音数量,并先存为最大值。
接着开始滑动窗口:
- 当原窗口第一个字母是元音的时候,要元音数量 - 1 。
- 当现窗口最后一个字母是元音的时候,要元音数量 + 1 。
每次循环完后记录下最大元音数量。
2.2 方法二:滑动窗口优化版
思路与算法:
这个方法在第一个方法的基础上,做了一个简单的优化:
如果窗口里已经全部都是元音了,没必要把后面的都遍历一遍,我们已经得到结果了不是吗?
k 比较小的时候可能大大减少遍历的位置!!!!
当当前元音数量等于 k 的时候,我们直接返回 k 。
三、代码
3.1 方法一:滑动窗口
Java版本:
java
class Solution {
public int maxVowels(String s, int k) {
ArrayList<Character> list = new ArrayList<>(Arrays.asList('a', 'e', 'i', 'o', 'u'));
int vowels = 0, maxVowels;
for (int i = 0; i < k; i++) {
if (list.contains(s.charAt(i))) {
vowels++;
}
}
maxVowels = vowels;
for (int i = k; i < s.length(); i++) {
if (list.contains(s.charAt(i - k))) {
vowels--;
}
if (list.contains(s.charAt(i))) {
vowels++;
}
maxVowels = Math.max(vowels, maxVowels);
}
return maxVowels;
}
}
C++版本:
cpp
class Solution {
public:
int maxVowels(string s, int k) {
vector<char> vowels = {'a', 'e', 'i', 'o', 'u'};
int maxVowels = 0, currentVowels = 0;
for (int i = 0; i < k; i++) {
if (find(vowels.begin(), vowels.end(), s[i]) != vowels.end()) {
currentVowels++;
}
}
maxVowels = currentVowels;
for (int i = k; i < s.length(); i++) {
if (find(vowels.begin(), vowels.end(), s[i - k]) != vowels.end()) {
currentVowels--;
}
if (find(vowels.begin(), vowels.end(), s[i]) != vowels.end()) {
currentVowels++;
}
maxVowels = max(currentVowels, maxVowels);
}
return maxVowels;
}
};
3.2 方法二:滑动窗口优化版
Java版本:
java
class Solution {
public int maxVowels(String s, int k) {
ArrayList<Character> list = new ArrayList<>(Arrays.asList('a', 'e', 'i', 'o', 'u'));
int vowels = 0, maxVowels;
for (int i = 0; i < k; i++) {
if (list.contains(s.charAt(i))) {
vowels++;
}
}
if (vowels == k) return k;
maxVowels = vowels;
for (int i = k; i < s.length(); i++) {
if (list.contains(s.charAt(i - k))) {
vowels--;
}
if (list.contains(s.charAt(i))) {
vowels++;
}
if (vowels == k) return k;
maxVowels = Math.max(vowels, maxVowels);
}
return maxVowels;
}
}
C++版本:
cpp
class Solution {
public:
int maxVowels(std::string s, int k) {
std::vector<char> list = {'a', 'e', 'i', 'o', 'u'};
int vowels = 0, maxVowels;
for (int i = 0; i < k; i++) {
if (std::find(list.begin(), list.end(), s[i]) != list.end()) {
vowels++;
}
}
if (vowels == k) return k;
maxVowels = vowels;
for (int i = k; i < s.length(); i++) {
if (std::find(list.begin(), list.end(), s[i - k]) != list.end()) {
vowels--;
}
if (std::find(list.begin(), list.end(), s[i]) != list.end()) {
vowels++;
}
if (vowels == k) return k;
maxVowels = std::max(vowels, maxVowels);
}
return maxVowels;
}
};
四、复杂度分析
4.1 方法一:滑动窗口
- **时间复杂度:**O(∣s∣),其中 ∣s∣ 是字符串 s 的长度。我们首先需要 O(k) 的时间求出前 k 个字母组成的子串包含的元音字母个数,在这之后还有 O(∣s∣−k) 个子串,每个子串包含的元音字母个数可以在 O(1) 的时间计算出,因此总时间复杂度为 O(∣s∣)。
- **空间复杂度:**O(1)。
4.2 方法二:滑动窗口优化版
- **时间复杂度:**O(∣s∣)。
- **空间复杂度:**O(1)。