头和结尾都是元音字母(aeiouAEIOU
)的字符串为元音字符串,其中混杂的非元音字母数量为其瑕疵度。比如:
"a"
,"aa"
是元音字符串,其瑕疵度都为 0
"aiur"
不是元音字符串(结尾不是元音字符)"abira"
是元音字符串,其瑕疵度为 2
给定一个字符串,请找出指定瑕疵度的最长元音字符子串,并输出其长度,如果找不到满足条件的元音字符子串,输出 0
。
子串:字符串中任意个连续的字符组成的子序列称为该字符串的子串。
首行输入是一个整数,表示预期的瑕疵度flaw,取值范围[0, 65535]
。
接下来一行是一个仅由字符a-z
和A-Z
组成的字符串,字符串长度(0, 65535]
。
输出为一个整数,代表满足条件的元音字符子串的长度。
0
asdbuiodevauufgh
3
满足条件的最长元音字符子串有两个,分别为uio
和auu
,长度为 3
。
2
aeueo
0
没有满足条件的元音字符子串,输出 0
1
aabeebuu
1
满足条件的最长元音字符子串有两个,分别为aabee
和eebuu
,长度为 5
本题很显然是要找到一个最长的滑动窗口,窗口需要满足以下两个条件:
k
个(即瑕疵度)窗口的辅音个数,可以用一个变量win_consonant_num
来维护即可。要特别注意一点,因为元音子串要求子串首尾的字符都是元音,我们必须固定left
的位置始终指向一个元音,这使得
left
右移的条件会和常规的滑窗问题略有不同。left
的起始位置以及滑窗的开始位置。Q1:对于每一个右指针right
所指的元素ch
,做什么操作?
Q2:什么时候要令左指针left
右移?left
对应的元素做什么操作?while
中的循环不变量是什么?
Q3:什么时候进行ans
的更新?
A1:如果ch
是一个辅音,则窗口中辅音个数win_consonant_num += 1
A2:win_consonant_num > k
,即滑窗子串所对应的瑕疵度超过了瑕疵度阈值k
,left
右移,直到left
指向一个元音。
A3:如果ch
是一个元音,且此时瑕疵度恰好为k
,那么可以更新答案。
# 题目:【不定滑窗】2023C-最长的指定瑕疵度的元音子串
# 分值:200
# 作者:许老师-闭着眼睛学数理化
# 算法:不定滑窗
# 代码看不懂的地方,请直接在群上提问
# 输入瑕疵度
k = int(input())
# 输入原字符串
s = input()
# 构建包含元音的集合,用于快速判断某字符是不是元音
vowel_set = set("aeiouAEIOU")
n = len(s)
# 初始化滑窗的左指针left是n
left = n
# 找到第一个元音
for i in range(n):
if s[i] in vowel_set:
left = i
break
# 如果经过上述循环后,left仍是n
# 说明s中不存在元音,也不存在符合要求的子串
# 直接输出0
if left == n:
print(0)
else:
ans = 0
# 初始化滑窗中的辅音个数为0
win_consonant_num = 0
# 进行滑窗,从下标left开始滑窗
for right, ch in enumerate(s[left:], left):
# A3:如果ch是一个元音,且瑕疵度恰好为k,那么可以更新答案。
if ch in vowel_set:
if win_consonant_num == k:
ans = max(ans, right-left+1)
# A1:如果ch是一个辅音,则窗口中辅音个数win_consonant_num += 1
else:
win_consonant_num += 1
# A2:即滑窗子串所对应的瑕疵度超过了瑕疵度阈值k,left右移,
# 由于元音子串的首尾必须均为元音
# 因此left需要持续右移直到以下两个条件均满足:
# 1. win_consonant_num <= k
# 2. s[left]指向一个元音
while left < n and (win_consonant_num > k or s[left] not in vowel_set):
if s[left] not in vowel_set:
win_consonant_num -= 1
left += 1
# 退出循环,ans即为答案
print(ans)
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 输入瑕疵度
int k = scanner.nextInt();
scanner.nextLine(); // 读取换行符
// 输入原字符串
String s = scanner.nextLine();
// 构建包含元音的集合
Set<Character> vowelSet = new HashSet<>();
vowelSet.add('a');
vowelSet.add('e');
vowelSet.add('i');
vowelSet.add('o');
vowelSet.add('u');
vowelSet.add('A');
vowelSet.add('E');
vowelSet.add('I');
vowelSet.add('O');
vowelSet.add('U');
int n = s.length();
int left = n;
// 找到第一个元音
for (int i = 0; i < n; i++) {
if (vowelSet.contains(s.charAt(i))) {
left = i;
break;
}
}
// 如果不存在元音
if (left == n) {
System.out.println(0);
} else {
int ans = 0;
int winConsonantNum = 0;
for (int right = left; right < n; right++) {
char ch = s.charAt(right);
// 如果 ch 是元音
if (vowelSet.contains(ch)) {
if (winConsonantNum == k) {
ans = Math.max(ans, right - left + 1);
}
} else { // 如果 ch 是辅音
winConsonantNum++;
// 如果滑窗子串对应的瑕疵度超过了阈值 k
while (left < n && (winConsonantNum > k || !vowelSet.contains(s.charAt(left)))) {
if (!vowelSet.contains(s.charAt(left))) {
winConsonantNum--;
}
left++;
}
}
}
// 输出结果
System.out.println(ans);
}
}
}
#include
#include
using namespace std;
int main() {
// 输入瑕疵度
int k;
cin >> k;
// 输入原字符串
string s;
cin.ignore(); // 忽略换行符
getline(cin, s);
// 构建包含元音的集合
unordered_set<char> vowelSet = {'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'};
int n = s.length();
int left = n;
// 找到第一个元音
for (int i = 0; i < n; i++) {
if (vowelSet.count(s[i]) == 1) {
left = i;
break;
}
}
// 如果不存在元音
if (left == n) {
cout << 0 << endl;
} else {
int ans = 0;
int winConsonantNum = 0;
int start = left;
for (int right = start; right < n; right++) {
char ch = s[right];
// 如果 ch 是元音
if (vowelSet.count(ch)) {
if (winConsonantNum == k) {
ans = max(ans, right - left + 1);
}
} else { // 如果 ch 是辅音
winConsonantNum++;
// 如果滑窗子串对应的瑕疵度超过了阈值 k
while (left < n && (winConsonantNum > k || !vowelSet.count(s[left]))) {
if (!vowelSet.count(s[left])) {
winConsonantNum--;
}
left++;
}
}
}
// 输出结果
cout << ans << endl;
}
return 0;
}
时间复杂度:O(N)
。仅需一次遍历数组。
空间复杂度:O(1)
。仅需若干常数变量。
华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!
课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化
每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!
60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁
可上全网独家的欧弟OJ系统练习华子OD、大厂真题
可查看链接 大厂真题汇总 & OD真题汇总(持续更新)
绿色聊天软件戳 od1336
了解更多