我编写了一个递归函数,它接受一个正整数数组(> 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循环内部,这让我感到困惑。任何人都可以帮我确定这个功能的时间复杂度吗?
答案 0 :(得分:2)
一般来说,在最坏的情况下,您将花费时间与(amount
/ denominations[0]
)*(amount
/ denominations[1]
)* ... *({{1 }} / amount
),其中n - 面额数。
这是因为您查看了每种面额的所有计数集。特定面额编号denominations[n]
的最大计数为i
/ amount
。
在实际情况中,您会提前停止该过程,但我认为它不会改变O((amount / geometric_average_denomination)^ n)。
虽然可以避免指数时间。为此,您可以使用动态编程方法。这是我的算法版本需要O(金额* n)时间:
denominations[i]
想法是填充size [n] [amount]的矩阵,其中每个元素(i,j)是使用具有索引&gt; = i的面额子集的amount = j的解的数量。您只需填写此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;
}
矩阵的每个元素一次,如果已经定义,则稍后重复使用。
使用它像:
cache