文章目录
- 题目描述与示例
- 题目描述
- 输入描述
- 输出描述
- 示例一
- 输入
- 输出
- 说明
- 示例二
- 输入
- 输出
- 说明
- 示例三
- 输入
- 输出
- 说明
- 解题思路
- 滑窗三问
- 滑窗三答
- 代码
- Python
- Java
- C++
- 时空复杂度
- 华为OD算法/大厂面试高频题算法练习冲刺训练
题目描述与示例
题目描述
头和结尾都是元音字母(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
,那么可以更新答案。
代码
Python
# 题目:【不定滑窗】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 = ibreak# 如果经过上述循环后,left仍是n
# 说明s中不存在元音,也不存在符合要求的子串
# 直接输出0
if left == n:print(0)
else:ans = 0# 初始化滑窗中的辅音个数为0win_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 += 1else: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 -= 1left += 1# 退出循环,ans即为答案print(ans)
Java
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++;// 如果滑窗子串对应的瑕疵度超过了阈值 kwhile (left < n && (winConsonantNum > k || !vowelSet.contains(s.charAt(left)))) {if (!vowelSet.contains(s.charAt(left))) {winConsonantNum--;}left++;}}}// 输出结果System.out.println(ans);}}
}
C++
#include <iostream>
#include <unordered_set>
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++;// 如果滑窗子串对应的瑕疵度超过了阈值 kwhile (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算法/大厂面试高频题算法练习冲刺训练
-
华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!
-
课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化
-
每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!
-
60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁
-
可上全网独家的欧弟OJ系统练习华子OD、大厂真题
-
可查看链接 大厂真题汇总 & OD真题汇总(持续更新)
-
绿色聊天软件戳
od1336
了解更多