求和:递归是必要的吗?递归算法是什么样的?

1 投票
6 回答
1747 浏览
提问于 2025-04-17 19:59
def numPens(n):
    """
    n is a non-negative integer

    Returns True if some non-negative integer combination of 5, 8 and 24 equals n
    Otherwise returns False.
    """
    if n < 5:
        return False
    N = n
    while N >= 0:
        if  N % 24 == 0 or N % 8 == 0 or N % 5 == 0: # if N / 24 is equal to 0 then we can buy N pens
            return True
        if N < 5:
            return False    # if N < 5 we cannot buy any pens

        if  N > 24:         # if N is greater than 24 , take away 24 and continue loop
            N -= 24
        elif N > 8:         # if N is greater than 8, take away 8 and continue loop
            N -= 8
        else:
            N -= 5          # else take away 5 and continue loop

我需要为一个测试创建这个函数,我在想这个问题是否可以用递归的方法来解决,或者有什么更有效的解决方案。我刚开始学习编程,所以任何帮助都非常感谢,谢谢。

6 个回答

1

显然,这是一个递归问题,下面的代码可能是最简单的:

def numPens(n):
    if n < 5:
        return False
    elif n==5 or n==8 or n==24:
        return True
    else:
        return numPens(n-5) or numPens(n-8) or numPens(n-24)

如果你想让它更高效、更稳健,可以自己进行改进。

3

有一些更高效的算法,它们的时间复杂度是O(1),也就是说它们的运行时间是固定的,不会随着输入的大小而变化。

比如,你可以把

if n > 40: 
    return True

作为你的基本情况之一!

你还可以通过维护一个查找表来让它变得更高效,这个查找表可以存储其他值(n < 40)。

你之所以能这样做,是因为这个原因:http://en.wikipedia.org/wiki/Coin_problem#n_.3D_2

6
if  N % 24 == 0 or N % 8 == 0 or N % 5 == 0

如果你去掉上面的取模(%)检查,那么你的算法就叫做贪心算法。它每次都减去能减去的最大数字。你可能注意到了,贪心算法并不总是有效。比如说,对于15,它会算成5 + 5 + 5,这个答案就是错的。

 15 (-8) --> 7 (-5) --> 2 --> False

通过加入取模检查,你改善了贪心算法,因为它现在能正确处理15了。但是它仍然有漏洞:比如说26可以表示为8 + 8 + 5 + 5。

 26 (-24) --> 2 --> False

要正确解决这个问题,你必须放弃贪心的方法。仅仅减去最大的数字并不总是够的。回答你的问题,是的,这里需要一个递归的解决方案。

def numPens(n):
    """
    n is a non-negative integer

    Returns True if some non-negative integer combination of 5, 8 and 24 equals n
    Otherwise returns False.
    """
    # Base case: Negative numbers are by definition false.
    if n < 0:
        return False

    # Base case: 0 is true. It is formed by a combination of zero addends,
    # and zero is a non-negative integer.
    if n == 0:
        return True

    # General case: Try subtracting *each* of the possible numbers, not just
    # the largest one. No matter what n-x will always be smaller than n so
    # eventually we'll reach one of the base cases (either a negative number or 0).
    for x in (24, 8, 5):
        if numPens(n - x):
            return True

    return False

这是解决这个问题最简单的方法,对于小一点的数字效果还不错。但是对于大数字来说,由于它会多次计算同样的数字,所以速度会很慢。一个优化的建议是使用动态规划来消除重复计算。

撰写回答