python 每次出现元音时反转字符串的函数?

edqdpe6u  于 2022-12-25  发布在  Python
关注(0)|答案(4)|浏览(165)

我正在尝试创建一个函数,对于字符串中的每一个元音,都将said-string反转(在这样做的时候包括元音)。这个函数对我的理解来说有点复杂,所以我需要一些帮助,也许是它的分解。但是,我只想使用我目前正在学习的运算符和语句(for/while和if)。如果可能的话,我也希望避免使用列表解析。

输入和输出应如下所示:

示例输入为reverse_per_vowel('aerith'),它返回'iraeth'

如果我们将此函数的过程分解为多个步骤,则应如下所示:

a)erith →(a)erith(* 第一个字母是元音,所以颠倒过来。但是,因为它是字符串中的第一个字母,所以没有可见的变化。
(ae)rith →(ea)rith(
第二个字母也是元音,所以字符串中的每个字母都是相反的。
(eari)th →(irae)th(
第四个字母是元音字母,所以它之前的所有字母都被反转,注意它是如何解释字符串中之前被反转的字母的。*)
正如你所看到的,字符串被反转的次数是累积的,我不太确定如何编写代码,但是,我尝试编写了函数的一个组件。
"我所尝试的"

vowellist = 'aeiouAEIOU'
sampleword = 'aerith'

indexlist = []
for i in range(len(sampleword)):
    if sampleword[i] in vowel_list:
        indexlist.append(i)
indexlist

输出:[0, 1, 3]
这个摘录没有反转字符串的任何部分,但是它返回了字符串应该被反转的索引。2我计划做的是把这些索引插回到样本单词中,然后使用[::-1]反转字符串的一部分。3但是,我不知道我该怎么做,也不知道这是否是个好主意。4任何帮助都将不胜感激。

dy1byipe

dy1byipe1#

如果有很多元音,那么重复的颠倒似乎可以避免,因为第二次颠倒多少是对前一次颠倒的撤销。
是的,你可以使用这个算法:

  • 创建两个字符串,它们以emppy开头,并将第二个字符串标记为“active”。
  • 按相反顺序访问输入字符:从最后到第一
  • 只要它们是辅音,就将它们添加到当前活动字符串中
  • 当它是元音时,将活动字符串切换到另一个字符串,并在那里添加元音
  • 在此过程结束时,反转第二个字符串并返回两个字符串的串联:
VOWELS = set("aeiouAEIOU")

def reverse_per_vowel(s):
    endings = ["", ""]
    side = 1
    for c in reversed(s):
        if c in VOWELS:
            side = 1 - side  # Toggle between 0 and 1
        endings[side] += c
    return endings[0] + endings[1][::-1]

由于这个算法不是在每次遇到元音时都反转,而是只在结尾处执行一次反转,因此它以线性时间复杂度运行,这与如果你按字面意思实现所描述的过程所得到的结果相反,后者的最坏情况时间复杂度为O(n²)。
通过这个复杂性分析,我假设用一个字符扩展一个字符串是一个恒定时间的过程,如果对此有疑问,那么就用两个字符列表来实现它,调用append,并在过程结束时执行join,以获得最终的字符串:

VOWELS = set("aeiouAEIOU")

def reverse_per_vowel(s):
    endings = [[], []]
    side = 1
    for c in reversed(s):
        if c in VOWELS:
            side = 1 - side  # Toggle between 0 and 1
        endings[side].append(c)
    
    return "".join(endings[0] + endings[1][::-1])
piok6c0g

piok6c0g2#

实现这一点的一个简单方法是使用递归:

vowels = set('aeiouAEIOU')

def reverse_per_vowel(s):
    if not s: # empty string
        return ''
    beforelast, last = s[:-1], s[-1]
    if last in vowels:
        return last + reverse_per_vowel(beforelast)[::-1]
    return reverse_per_vowel(beforelast) + last

print(reverse_per_vowel('aerith')) # iraeth
atmip9wb

atmip9wb3#

使用列表使其非常简单明了:

def reverse_per_vowel(word):
    result = []
    for letter in word:
        result.append(letter)
        if letter in 'aeiouAEIOU':
            result.reverse()
    return ''.join(result)

对于您的示例单词,它比目前发布的所有其他解决方案都要快,对于一个包含1000个字母的单词,它也是如此('aerith' * 167),只有@trincot的第二个解快一点,其他的都慢2到10倍,最后当然真的输给了trincot的第二个解,后者在10,000个字母时快5倍,在100个字母时,000个字母的速度快了46倍。
这是另一个线性时间的,比trincot的快一点(测试了多达一百万个字母的字符串),它把字母放入一个双端队列中,这样它就可以有效地向左或向右追加,并且它有一个标志来告诉结果当前是否是反向的。

from collections import deque

def reverse_per_vowel(word):
    result = deque()
    reverse = False
    for letter in word:
        if not reverse:
            result.append(letter)
        else:
            result.appendleft(letter)
        if letter in 'aeiouAEIOU':
            reverse = not reverse
    if reverse:
        result.reverse()
    return ''.join(result)
ghhkc1vu

ghhkc1vu4#

只需简单修改for循环和一些高级切片就可以做到这一点:

vowellist = 'aeiouAEIOU'
sampleword = 'aerith'

for i in range(len(sampleword)):
    if sampleword[i] in vowellist:
        sampleword = sampleword[i::-1] + sampleword[i + 1:]

print(sampleword)

每次迭代,如果元音出现,你可以只重新分配字符串与新的部分颠倒.输出:

iraeth

相关问题