繁体   English   中英

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

[英]Counting vowels in a string using recursion

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

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

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

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

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

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

第二步最终将字符串减少到零长度,从而结束递归。 或者,可以使用尾递归实现相同的过程 - 不是因为CPython没有实现尾递归消除而在性能方面有任何不同。

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

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

  • 如果字符串为空,则返回0。
  • 如果字符串不为空且第一个字符是元音,则返回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

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

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

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的总和)。

参考文献:

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

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

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

这是直截了当的方法:

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

如果这是感兴趣的话,请看这篇博客文章

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM