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

Java 减少递归子集和算法的运行时间,java,algorithm,recursion,big-o,subset-sum,Java,Algorithm,Recursion,Big O,Subset Sum,我有一个递归DFS算法,可以正确地计算子集和的数量。然而,这种方法的运行时间是荒谬的,而且是指数级的。例如,当arr包含以下集合时。我们要找的总数是50。arr已删除所有重复项和大于或等于50的数字。然后对数组进行排序 二十一, 3. 42 10 13 17 33 26 19 7. 11 30 24 2. 五, arr包含按排序顺序排列的单词列表 k是数组的初始大小 sum是我们在子集中查找的总和,在本例中为50 public static void recDfs(ArrayList<I

我有一个递归DFS算法,可以正确地计算子集和的数量。然而,这种方法的运行时间是荒谬的,而且是指数级的。例如,当
arr
包含以下集合时。我们要找的总数是50。
arr
已删除所有重复项和大于或等于50的数字。然后对数组进行排序

二十一, 3. 42 10 13 17 33 26 19 7. 11 30 24 2. 五,

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);
}
公共静态void recDfs(ArrayList arr、int k、int sum){
如果(总和=0){
计数器++;
返回;
}
如果(总和=0&&k==0){
返回;
}
recDfs(arr,k-1,sum-arr.get(k-1));
recDfs(arr,k-1,sum);
}
这将非常快地给出正确的结果,如下所示

经过的时间:=0.004838总计50的子集有51个 生成成功(总时间:0秒)

然而,当我们在数组中有一个新的集合时,该算法会呈指数增长,例如

九十九 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 十九,

当我们使用新数组再次调用
recDfs
时,新数组也会被排序并删除重复项(总和为107),运行时间是荒谬的,但是打印了正确数量的子集

经过的时间:=19853.771050总计107的子集数量为1845 构建成功(总时间:330分54秒)


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

如果我正确理解这一点,可以进行一些小优化:

 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);
}
publicstaticvoidrecdfs(int[]arr,int k,int sum){
如果(总和<0)返回;
如果(总和=0){
计数器++;
返回;
}
如果(k==0){
返回;
}
recDfs(arr,k-1,sum-arr[k-1]);
recDfs(arr,k-1,sum);
}

如果我正确地解释了这一点,那么如果总和小于0,您可以保留分支,这可以节省大量时间。(如果存在负数,则无法执行)其他次要优化是使用int数组。这应该比使用整数数组列表节省一些时间。如果你想变得更花哨,你可以使用多个线程。

大提示:动态编程,记忆;)它也可以通过制表来完成,但是代码看起来会非常不同,因为您将自下而上而不是自上而下。无论如何,在DP中,这是一个很好的练习。