【问题标题】:Counting vowels in a string using recursion使用递归计算字符串中的元音
【发布时间】:2012-10-04 08:48:50
【问题描述】:

我知道递归是一个函数调用自身的时候,但是我无法弄清楚如何让我的函数调用它自己以获得所需的结果。我需要简单地计算给函数的字符串中的元音。

def recVowelCount(s):
    'return the number of vowels in s using a recursive computation'
    vowelcount = 0
    vowels = "aEiou".lower()
    if s[0] in vowels:
        vowelcount += 1
    else:
        ???

多亏了这里的一些见解,我最终想到了这个。

def recVowelCount(s):
'return the number of vowels in s using a recursive computation'
vowels = "aeiouAEIOU"
if s == "":
    return 0
elif s[0] in vowels:
    return 1 + recVowelCount(s[1:])
else:
    return 0 + recVowelCount(s[1:])

【问题讨论】:

  • 不要使用else 块。无论如何,您都需要递归。
  • 好的,我看看我能想出什么。
  • 作业标签已被弃用;请不要使用它。如果您认为这很重要,请在您的问题中提及家庭作业。 :-)

标签: python string recursion count


【解决方案1】:

使用切片删除第一个字符并测试其他字符。您不需要 else 块,因为您需要为每种情况调用该函数。如果你把它放在 else 块中,那么当你的最后一个字符是元音时,它不会被调用:-

### Improved Code

def recVowelCount(s):
    'return the number of vowels in s using a recursive computation'

    vowel_count = 0 
    # You should also declare your `vowels` string as class variable  
    vowels = "aEiou".lower()

    if not s:
        return 0

    if s[0] in vowels:
        return 1 + recVowelCount(s[1:])

    return recVowelCount(s[1:])

# Invoke the function
print recVowelCount("rohit")   # Prints 2

这将调用您的递归函数,并使用新字符串切片第一个字符。

【讨论】:

  • 我应该把 slice 语句放在哪里?
  • @Amber。哦,是的.. 已编辑.. 你应该把它放在你的 if 之外。在任何情况下都应该调用它。您的最后一个字符是否为元音。
  • 这里还有一个问题是什么都没有返回。
  • @Amber。是的,OP 可以从函数中返回 vowelCount。好的,我会发布完整的函数。
  • 我会在最后打印(vowelcount)。
【解决方案2】:

您的函数可能需要大致如下所示:

  • 如果字符串为空,返回0。
  • 如果字符串不为空且第一个字符是元音,则返回 1 + 对字符串其余部分的递归调用结果
  • 如果字符串不为空且第一个字符不是元音,则返回对字符串其余部分的递归调用的结果。

【讨论】:

  • 这条评论最有帮助,我没有抄袭任何人的作品。
【解决方案3】:

试试这个,这是一个简单的解决方案:

def recVowelCount(s):
    if not s:
        return 0
    return (1 if s[0] in 'aeiouAEIOU' else 0) + recVowelCount(s[1:])

它考虑了元音是大写还是小写的情况。这可能不是递归遍历字符串的最有效方式(因为每个递归调用都会创建一个新的切片字符串),但它很容易理解:

  • 基本情况:如果字符串为空,则元音为零。
  • 递归步骤:如果第一个字符是元音,则在解中加 1,否则加 0。无论哪种方式,通过删除第一个字符来推进递归并继续遍历字符串的其余部分。

第二步最终会将字符串减少到零长度,从而结束递归。或者,可以使用 tail recursion 来实现相同的过程 - 鉴于 CPython 没有实现 tail recursion elimination,它不会对性能产生任何影响。

def recVowelCount(s):
    def loop(s, acc):
        if not s:
            return acc
        return loop(s[1:], (1 if s[0] in 'aeiouAEIOU' else 0) + acc)
    loop(s, 0)

只是为了好玩,如果我们取消解决方案必须是递归的限制,这就是我的解决方法:

def iterVowelCount(s):
    vowels = frozenset('aeiouAEIOU')
    return sum(1 for c in s if c in vowels)

无论如何这都有效:

recVowelCount('murcielago')
> 5

iterVowelCount('murcielago')
> 5

【讨论】:

  • 我希望我在学校时有堆栈溢出来做作业:P ... +1 以获得很好的答案
  • 实际上,recVowelCount 不起作用(试试recVowelCount('a'*1000)
  • @thg435 这是 Python 的错,而不是算法的错。尽管可以增加递归深度并且可以将算法重写为尾递归,但这并没有改变 Python 没有针对尾调用消除进行优化的事实。 Python中所有足够大的递归算法都注定要失败。
  • 大声笑实际上我更喜欢理解事物,而不是盲目地从这个站点复制它们。我通常只在没有其他选择时才问。我的教授正在卡尔加里参加会议,无法回复我的电子邮件,所以我来到这里。
  • @ÓscarLópez:完全可以在 python 中以堆栈安全的方式编写尾递归算法。语言没有提供开箱即用的功能这一事实是幼稚编码的一个糟糕的借口。
【解决方案4】:

这里有一个函数式编程方法供你学习:

map_ = lambda func, lst: [func(lst[0])] + map_(func, lst[1:]) if lst else []
reduce_ = lambda func, lst, init: reduce_(func, lst[1:], func(init, lst[0])) if lst else init

add = lambda x, y: int(x) + int(y)
is_vowel = lambda a: a in 'aeiou'

s = 'How razorback-jumping frogs can level six piqued gymnasts!'
num_vowels = reduce_(add, map_(is_vowel, s), 0)

想法是将问题分为两步,第一步(“map”)将数据转换为另一种形式(字母 -> 0/1),第二步(“reduce”)将转换后的项目收集到一个单个值(1 的总和)。

参考资料:

另一个更高级的解决方案是将问题转换为tail recursive 并使用trampoline 来消除递归调用:

def count_vowels(s):
    f = lambda s, n: lambda: f(s[1:], n + (s[0] in 'aeiou')) if s else n
    t = f(s, 0)
    while callable(t): t = t()
    return t

请注意,与简单的解决方案不同,此解决方案可以处理非常长的字符串,而不会导致“超出递归深度”错误。

【讨论】:

    【解决方案5】:

    这是直截了当的方法:

    VOWELS = 'aeiouAEIOU'
    
    def count_vowels(s):
        if not s:
            return 0
        elif s[0] in VOWELS:
            return 1 + count_vowels(s[1:])
        else:
            return 0 + count_vowels(s[1:])
    

    这里也是一样,代码少了:

    def count_vowels_short(s):
        if not s:
            return 0
        return int(s[0] in VOWELS) + count_vowels_short(s[1:])
    

    这是另一个:

    def count_vowels_tailrecursion(s, count=0):
        return count if not s else count_vowels_tailrecursion(s[1:], count + int(s[0] in VOWELS))
    

    很遗憾,这对于长字符串会失败。

    >>> medium_sized_string = str(range(1000))
    >>> count_vowels(medium_sized_string)
    ...
    RuntimeError: maximum recursion depth exceeded while calling a Python object
    

    如果您对此感兴趣,请查看this blog article

    【讨论】:

      猜你喜欢
      • 2019-09-01
      • 2021-05-19
      • 1970-01-01
      • 2013-11-15
      • 2018-04-30
      • 2020-03-15
      • 1970-01-01
      • 2013-07-21
      • 1970-01-01
      相关资源
      最近更新 更多