贪婪递归算法的时间复杂度
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了贪婪递归算法的时间复杂度相关的知识,希望对你有一定的参考价值。
我已经编码了一个贪婪的递归算法,以找出进行给定更改的最小硬币数量。现在,我需要估计其时间复杂度。由于算法根据相同的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)
什么是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)
,其中n
是len(coins)
。
每个递归调用将更改减少至少1,并且没有分支(也就是说,递归树实际上是一条直线,因此实际上不需要递归)。您的运行时间为O(n)
。
以上是关于贪婪递归算法的时间复杂度的主要内容,如果未能解决你的问题,请参考以下文章