贪婪递归算法的时间复杂度

问题描述 投票:2回答:2

我已经编码了一个贪婪的递归算法,以找出进行给定更改的最小硬币数量。现在,我需要估计其时间复杂度。由于算法根据相同的i(n * n)嵌套了“ ifs”,而内部块将递归调用减半(log(2)n),我相信正确的答案可能是O(n * log(n) ),计算如下:

n * log2(n)* O(1)

[请给我您有关我的分析是否正确的想法,并随时提出改进我贪婪的递归算法的建议。

这是我的递归算法:

coins = [1, 5, 10, 21, 25]
coinsArraySize = len(coins)
change = 63
pickedCoins = []

def findMin(change, i, pickedCoins):              
    if (i>=0):
        if (change >= coins[i]):               
           pickedCoins.append(coins[i])
           findMin(change - coins[i], i, pickedCoins)
        else:           
           findMin(change, i-1, pickedCoins)
findMin(change, coinsArraySize-1, pickedCoins)
python recursion time-complexity big-o greedy
2个回答
0
投票

什么是n?运行时间取决于数量和特定硬币。例如,假设您有一百万个硬币(从1到1,000,000),并尝试对1进行更改。在最终找到它可以使用的最大硬币之前,该代码将经过一百万个递归级别(1)。最后,如果您只有一个硬币([1])并尝试以1,000,000进行零钱,那么您最终会发现同样的事情-然后您立即找到了该硬币,但经过一百万个级别对该硬币进行了百万次的深度挑选。

这是一个非递归版本,在这两个方面均得到了改进:使用二进制搜索来查找下一个可用硬币,一旦找到合适的硬币,请尽可能多地使用它。

def makechange(amount, coins):
    from bisect import bisect_right
    # assumes `coins` is sorted. and that coins[0] > 0
    right_bound = len(coins)
    result = []
    while amount > 0:
        # Find largest coin <= amount.
        i = bisect_right(coins, amount, 0, right_bound)
        if not i:
            raise ValueError("don't have a coin <=", amount)
        coin = coins[i-1]
        # How many of those can we use?
        n, amount = divmod(amount, coin)
        assert n >= 1
        result.extend([coin] * n)
        right_bound = i - 1
    return result

[如果要求以一枚硬币将一百万换成一百万,仍需要花费O(amount)时间,但因为它必须建立一百万个1的副本的结果列表。如果有一百万枚硬币,而您要求更改为1,这是O(log2(len(coins)))时间。可以通过将输出格式更改为字典,将硬币映射到使用硬币的次数来大幅度减少第一个硬币。然后,第一种情况将缩短为O(1)时间。

照原样,花费的时间与结果列表的长度成正比,再加上一些二进制搜索(等于所用不同硬币的数量)所花费的时间(通常是微不足道)。因此,“坏情况”是需要使用每种硬币的情况。例如,

>>> coins = [2**i for i in range(10)]
>>> makechange(sum(coins), coins)
[512, 256, 128, 64, 32, 16, 8, 4, 2, 1]

本质上是O(n + n log n),其中nlen(coins)


0
投票

每个递归调用将更改减少至少1,并且没有分支(也就是说,递归树实际上是一条直线,因此实际上不需要递归)。您的运行时间为O(n)

© www.soinside.com 2019 - 2024. All rights reserved.