减少递归子集求和算法的运行时间

时间:2015-03-03 15:06:11

标签: java algorithm recursion big-o subset-sum

我有一个递归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秒)

我正在寻找更好的方法来实现这个算法。

1 个答案:

答案 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节省一点时间。如果你想得到想象,你可以使用多个线程。