有人能告诉我这段代码的复杂性(Big O符号首选)吗?它找到了最少数量的"硬币"需要制定目标总和。 为此,它计算从1开始的每个数字的最小硬币数量。每个数字根据可能的总和数量来计算,并使用成本最小的数字。一个例子希望能让这个更清晰
如果"硬币"是{1,3,4},目标是13然后它从1到13迭代,其中2的成本最小为(0 + 2,1 + 1),c(5)是最小的成本( c(0)+ c(5),c(1)+ c(4),c(2)+ c(3))等,直至c(13)
这是背包问题的一个版本,我想知道如何定义其复杂性?
代码:
import java.util.*;
public class coinSumMinimalistic {
public static final int TARGET = 12003;
public static int[] validCoins = {1, 3, 5, 6, 7, 10, 12};
public static void main(String[] args) {
Arrays.sort(validCoins);
sack();
}
public static void sack() {
Map<Integer, Integer> coins = new TreeMap<Integer, Integer>();
coins.put(0, 0);
int a = 0;
for(int i = 1; i <= TARGET; i++) {
if(a < validCoins.length && i == validCoins[a]) {
coins.put(i, 1);
a++;
} else coins.put(i, -1);
}
for(int x = 2; x <= TARGET; x++) {
if(x % 5000 == 0) System.out.println("AT: " + x);
ArrayList<Integer> list = new ArrayList<Integer>();
for(int i = 0; i <= x / 2; i++) {
int j = x - i;
list.add(i);
list.add(j);
}
coins.put(x, min(list, coins));
}
System.out.println("It takes " + coins.get(TARGET) + " coins to reach the target of " + TARGET);
}
public static int min(ArrayList<Integer> combos, Map<Integer, Integer> coins) {
int min = Integer.MAX_VALUE;
int total = 0;
for(int i = 0; i < combos.size() - 1; i += 2) {
int x = coins.get(combos.get(i));
int y = coins.get(combos.get(i + 1));
if(x < 0 || y < 0) continue;
else {
total = x + y;
if(total > 0 && total < min) {
min = total;
}
}
}
int t = (min == Integer.MAX_VALUE || min < 0) ? -1:min;
return t;
}
}
编辑:经过研究,我认为复杂度为O(k * n ^ 2),其中n是目标,k是提供的硬币数量,这是正确的吗?
答案 0 :(得分:5)
我认为你提供的代码有点混乱。所以这篇文章更多的是关于概念算法而不是真实算法。这可能有点不同,因为例如ArrayList<T>
中的插入不是 O(1),但我确信您可以使用良好的数据结构(例如{{1} } s)为此让所有操作都在恒定的时间内运行。
您的算法基本上做的是:
参数是:
第一个观察是(2.)的每个步骤需要 O(s ^ 2)时间, s 在开始时集合中的元素数量迭代:这是因为你将每个值与每个值匹配。
第二个观察结果是,集合中的元素永远不会超过请求的值。这意味着 s 受 O(r)的限制(我们假设所有硬币都是整数,因此该集合最多可包含从0到 r的所有整数值-1 的)。因此,步骤(2。)具有O(r ^ 2)的最大时间复杂度。
此外,该集合逐步演变:在每次迭代中,您将始终构造一个 new 值,该值至少比目前的最大值大一个。因此,该算法将执行最大 O(r)迭代。
这意味着该算法的时间复杂度为 O(r ^ 3): r 次 O(r ^ 2)
为什么行为是指数性的,因此至少是NP难?
第一个论点是,它取决于你如何表示输入:在许多情况下,数字是使用 radix 大于或等于{的系统来表示的{1}}。这意味着对于 k 字符,您可以使用 g 基数来表示使用 O(g ^ k)进行缩放的值。因此呈指数级。换句话说,如果使用LinkedList<T>
位数,最坏情况, r = O(2 ^ 32)。因此,如果您将此作为输入,则存在指数部分。如果您使用一元表示法对目标进行编码,则算法位于 P 中。但当然这有点像 padding-argument :假设你提供了足够无用的输入数据(指数甚至超指数),所有算法都在 P 中,但是你不会为此付出太多。
第二个参数是,如果您将所请求的值保留在输入之外,则只能声明您以 n 币开头。您知道迭代次数是固定的:您将目标值视为未知常量。每次迭代,2
潜在正方形中的值总数。因此,这意味着计算工作是:
32
很明显,这种行为在 n 中呈指数形式。