我有一个递归DFS算法,可以正确计算子集总和的数量。但是,这种方法的运行时间是荒谬的,而且非常指数。例如,当arr
包含下面的集合时。我们要查找的总和是50. arr
包含所有重复项,数字大于或等于50。然后对数组进行排序。
21 3 42 10 13 17 33 26 19 7 11 三十 24 2 5
arr
包含按排序顺序排列的单词列表
k
是数组的初始大小
sum
是我们在子集中寻找的总和,在本例中是50
public static void recDfs(ArrayList<Integer> arr, int k, int sum) {
if (sum == 0) {
counter++;
return;
}
if (sum != 0 && k == 0) {
return;
}
recDfs(arr, k - 1, sum - arr.get(k - 1));
recDfs(arr, k - 1, sum);
}
这将非常快速地给出正确的结果,发布在
下面经过的时间:= 0.004838有51个子集的总和为50 建立成功(总时间:0秒)
然而,当我们在数组中有一个新的集合时,这个算法会以指数方式增加。
99 49 1 7 23 83 72 6 202 78 26 79 351 34 107 76 38 50 32 62 71 9 101 77 81 92 89 66 97 57 33 75 68 93 100 28 42 59 29 14 122 24 60 2 37 192 73 84 31 4 87 65 19
当我们再次调用recDfs
时,新数组也被排序并删除重复项,其总和为107,但运行时间是荒谬的,但打印的子集数量正确。
经过的时间:= 19853.771050有1845个子集的数量总和为107 建立成功(总时间:330分54秒)
我正在寻找更好的方法来实现这个算法。
答案 0 :(得分:4)
如果我理解正确的话,可以进行一些小的优化:
public static void recDfs(int[] arr, int k, int sum) {
if (sum < 0) return;
if (sum == 0) {
counter++;
return;
}
if (k == 0) {
return;
}
recDfs(arr, k - 1, sum - arr[k - 1]);
recDfs(arr, k - 1, sum);
}
如果我正确地解释了这一点,如果总和小于0可以保释分支,这可以节省大量时间。 (如果有负数则无法完成)其他次要优化是使用int数组。这应该比使用整数的ArrayList节省一点时间。如果你想得到想象,你可以使用多个线程。