使用递归计算字符串中的元音

时间:2012-10-13 22:40:32

标签: python string recursion count

我理解递归就是函数调用自身的时候,但我无法弄清楚如何让我的函数自我调用以获得所需的结果。我需要简单地计算赋予函数的字符串中的元音。

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:])

5 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:3)

您的功能可能需要看起来像这样:

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

答案 2 :(得分: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

这将使用带有第1个字符的新字符串调用递归函数。

答案 3 :(得分:0)

这是一种函数式编程方法供您学习:

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)

这个想法是将问题分成两个步骤,其中第一个(“地图”)将数据转换为另一个形式(字母 - > 0/1),第二个(“减少”)将转换后的项目转换为一个单一的值(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

请注意,与天真的解决方案不同,这个解决方案可以使用非常长的字符串,而不会导致“超出递归深度”错误。

答案 4 :(得分:0)

这是一种直截了当的方法:

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