以下是我提出的代码:
static void findNumbers(int[] list, int index, int current, int goal, String result)
{
if (list.length < index || current>goal)
return;
for (int i = index; i < list.length; i++) {
if (current + list[i] == goal) {
System.out.println(result + " " + String.valueOf(list[i]));
}
else if (current + list[i] < goal) {
findNumbers(list, i + 1, current + list[i], goal, result + " " + String.valueOf(list[i]));
}
}
}
使用以下方式调用:
findNumbers(array, starting_index, current_sum_till_now, target_sum, "");
有人可以帮助我弄清楚这段代码的时间复杂性,我相信它是指数级的。
解决此问题的最佳方法是什么?它是否正在使用回溯?
答案 0 :(得分:4)
有人指出我犯了一个错误。当我应该添加它们时,我正在增加递归调用的复杂性。所以C(N) = C(N-1) + C(N-2) + ...
。这同样适用于C(N-1)
,C(N-2)
等。这意味着复杂性不是'O(N!)
。
这让我从另一个角度思考算法。它正在检查每个可能的子集。由于有2^N - 1
个可能的子集(不考虑空子集),因此复杂度为O(2^N)
,我认为这是您原来的赌注。
答案 1 :(得分:1)
您可以修改您的代码,使其工作原则是“如果数字是好的 - 添加它;忽略任何条件跳过当前数字”。在这种情况下,代码将是:
static void findNumbers(int[] list, int index, int current, int goal, String result)
{
if (list.length <= index || current>goal) // I've added the "=" which is missing in your code.
return;
if (current + list[index] == goal) {
System.out.println(result + " " + String.valueOf(list[i]));
}
else if (current + list[index] < goal) {
findNumbers(list, index + 1, current + list[i], goal, result + " " + String.valueOf(list[i]));
}
findNumbers(list, index + 1, current, goal, result);
}
在这种情况下,复杂度为O(2^n)
,对n=>5
然后O(n!)
更好。
正如所指出的,如果对数组进行排序,则复杂性会降低。这意味着您可以将第二个递归调用放在else if
中,因为您将确保后面的所有数字都大于当前list[index]
,这意味着跳过此值没有用,因为此调用的所有后续分支都是如此不会生成任何有效的子集。
在这种情况下,最糟糕的情况是O(2^l)
,其中l
是一个数字的索引,该数字大于您的目标并且在您的数组中,或n
如果这样的数字不存在。
电话应该是:findNumbers(list,0,0,goal,"")
答案 2 :(得分:0)
正如刚刚指出的那样,它比N ^ 2更糟,事实上它看起来像是O(N!)。您可以保存一些,因为您可以提前退出某些循环,但保存程度取决于消除可能性的速度。
就更优化的解决方案而言,您将要努力,这是递归的一个很好的例子,因为任何基于循环的构造都将是可怕的。您可以通过预先对数据进行排序来节省一些时间,以便首先获得更大的值,从而更快地达到目标(这将基本上消除列表中立即大于目标的任何内容)。在消除了太大的条目后,我不确定它是否会直接帮助,因为您仍然需要将所有内容与所有内容进行比较,但它可能会改进处理器分支预测。
答案 3 :(得分:0)
这是一种使用动态编程和背包类比的方法: -
按升序对集合进行排序
评估子集直到list[i] <= N
解决背包的容量N和物品的价值和重量为list[i]
如果最终背包容量N ==最大利润,那么至少存在一个解决方案子集。
使用成本矩阵回溯所有背包解决方案并获取所有解决方案子集。
时间复杂度: O(|S|*N + K) |S|- length of set and K is number of subsets.
这是伪多项式时间算法。
注意:问题是NP-hard没有发现多项式时间算法。
编辑: - 从布尔矩阵中回溯解决方案
void retrace(int n,boolean[] solution,int target) {
if(n>=0) {
if(table[target][n-1]) {
solution[n] = false;
retrace(n-1,solution,target);
}
if(table[target-numbers[n]][n-1]) {
solution[n] = true;
retrace(n-1,solution,target-numbers[n]);
}
}
else {
printf("\nsubset:-\n");
for(int i=0;i<solution.length;i++) {
if(solution[i]) {
printf(number[i]+" ");
}
}
}
}
Call : - retrace(numbers.length-1,new boolean[numbers.length],target);