题目描述:
开头和结尾都是元音字母(aeiouAEIOU)的字符串为元音字符串,其中混杂的非元音字母数量为其瑕疵度。
“a” 、“aa”是元音字符串,其瑕疵度都为 0
“aiur”不是元音字符串(结尾不是元音字符)
“abira”是元音字符串,其瑕疵度为 2
给定一个字符串,请找出指定瑕疵度的最长元音字符子串,并输出其长度,如果找不到满足条件的元音字符子串,输出 0。
flaw=int(input())
s=input()
#不重复选择set
vowels=set('aeiouAEIOU')
n=[]
for i in range(len(s)):
if s[i] in vowels:
#n记录s中是元音字符的位置,作为新的数组
n.append(i)
l,r=0,0
length=[]
#r作为数组的序号,不能=n的长度,否则列表超限
while r<len(n):
#lengthdiff记录s中两个元音之间的间隔个数,也就是这里的瑕疵数
#n[r]-n[l]表示在n数组里,左右指针分别对应s中的元音字符的序号
#如果左右指针相邻,则间隔数=序号差-1;
#但是左右指针的位置会移动,左右指针的移动数=r-l;左右指针指向同一个字符,则此移动数=0
#所以间隔数=序号差-左右指针的移动数=n[r]-n[l]-(r-l)
lengthdiff=n[r]-n[l]-(r-l)
#大于瑕疵数了,l往后走,寻找下一个等于瑕疵数的子串
if lengthdiff>flaw:
l+=1
else:
if lengthdiff==flaw:
length.append(n[r]-n[l]+1)
r+=1
if len(length)==0:
print(0)
else:
print(max(length))
这道题最难理解的地方在于计算瑕疵度:
lengthdiff=n[r]-n[l]-(r-l)
通过厚德载物这位博主的讲解,具体操作过程如下图:
输入:
0
asdbuidevauufgh
在输入字符串中,属于元音字符的序号是:0、4、5、6、8、10、11、12
蓝色箭头表示左指针,另一个颜色表示右指针
计算瑕疵数可以理解为计算两个元音之间的间隔
n[r]、n[l] 表示左、右指针指向新列表中元音的序号
n[r]-n[l] 在图中表示:
0-0 | a→a |
4-0 | u→a |
5-4 | i→u |
6-4 | o→u |
从表格很直观看出:
1、指向同一个元音,瑕疵数=0(这里的瑕疵数至少是两个元音以上讨论)
2、不相邻的元音(指在输入字符串中不相邻,即图中方块里的序号不连续),瑕疵数=3
3、相邻的元音,瑕疵数=0
4、连续相邻的元音,瑕疵数=0
但是n[r]-n[l]只是表示了下一个元音到上一个元音在输入字符串中的移动步数
r-l 表示右指针到左指针在新组成的元音列表中的移动步数
若两个指针指向同一个元音序号,则 r-l=0
若两个指针指向相邻元音序号,则 r-l=1
所以,两个指针指向不同元音序号,则 r-l=元音间的移动步数
所以,瑕疵数=两个元音之间的间隔=非元音个数=两个元音在输入字符串中的移动步数(包括了非元音和元音)-元音间的移动步数(只有元音)
移动步数+1=个数
所以,上式也可理解为:
瑕疵数=左右指针指向的非元音个数=左右指针指向的全部字符个数-左右指针指向的元音字符个数={两个元音在输入字符串中的移动步数(包括了非元音和元音)+1}-{元音间的移动步数(只有元音)+1}
然后,计算的瑕疵数与给定的瑕疵数进行比较。一共有三种情况:
lengthdiff>flaw,l++
lengthdiff==flaw,r++
lengthdiff<flaw,r++
最后,输出指定瑕疵度lengthdiff==flaw的最长元音字符子串的长度=max(列表中,下一个元音到上一个元音在输入字符串中的移动步数+1)=max(列表中,n[r]-n[l]+1)
在这里用 n[r]-n[l] 或 r-l 是同样的,因为最长元音字符子串是连续的,无论是输入子串中的连续(如图中,6-4,12-10),还是新列表中的连续(3-1,7-5)表示的都是从字符o-u,u-a
这里的长度还+1,是移动步数为2,则个数就为3;移动步数为n,则个数就为n+1