[英]Time complexity of a non-trivial recursive function
我写了一个递归函数,它接受一个正整数(> 0)( denominations
)和一个整数值( amount
)的数组,并返回仅使用数组中的整数获取值的方式的数量。 因此,例如,整数数组可以被视为变化,整数值被视为您必须支付的金额。 该功能返回您可以支付收银员的方式。 例如:
amount
= 4, denominations
= [1,2,3,4]
这应该返回5
我测试了我的功能,它工作正常。 调用函数时,参数acc
和index
传递为0.这是函数:
public int count_number_of_ways(int amount, int acc, int index, int[] denominations) {
if (acc > amount) return 0;
if (amount == acc) return 1;
int len = denominations.length;
int count = 0;
while (acc < amount) {
for (int i = index + 1; i < len; i++) {
count += count_number_of_ways(amount, acc + denominations[i], i, denominations);
}
acc += denominations[index];
if (acc > amount) return count + 0;
if (acc == amount) return count + 1;
}
return count + 0;
}
我试图计算这个函数的时间复杂度,但碰到了一堵砖墙。 递归调用是在for循环中的for循环内部,这让我感到困惑。 谁能帮我确定这个功能的时间复杂度?
一般来说,在最坏的情况下,您将花费时间与( amount
/ denominations[0]
)*( amount
/ denominations[1]
)* ... *( amount
/ denominations[n]
)成amount
,其中n - 面额数。
这是因为您查看了每种面额的所有计数集。 并且特定面额数i
最大计数是amount
/ denominations[i]
。
在实际情况下,您会提前停止该过程,但我认为它不会改变O((amount / geometric_average_denomination)^ n)。
但是可以避免指数时间。 为此,您可以使用动态编程方法。 这是我的算法版本需要O(金额* n)时间:
public static int count_number_of_ways(int amount, int index, Integer[][] cache, int[] denominations) {
if (cache == null)
cache = new Integer[denominations.length][amount + 1];
if (amount == 0) {
int ret = 1;
cache[index][amount] = ret;
return ret;
}
if (cache[index][amount] != null) {
return cache[index][amount];
}
int ret = 0;
if (index + 1 < denominations.length)
ret += count_number_of_ways(amount, index + 1, cache, denominations);
if (amount >= denominations[index])
ret += count_number_of_ways(amount - denominations[index], index, cache, denominations);
cache[index][amount] = ret;
return ret;
}
该想法是填充大小[n] [金额]的矩阵,其中每个元素(i,j)是使用具有索引> = i的面额子集的金额= j的解的数量。 您只需填充此cache
矩阵的每个元素一次,如果已经定义,则稍后重复使用它。
使用它像:
int ret = count_number_of_ways(amount, 0, null, denominations)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.