给定一个由整数和和组成的数组,任务是查找是否存在给定数组的子集,其总和等于给定和

时间:2020-03-19 17:50:18

标签: java algorithm recursion data-structures dynamic-programming

这是我编写的函数。

    public static boolean existsSum(int[] arr, int n, int sum){
            if(sum==0)
                return true;
            if(n<=0)
                return false;
            if(arr[n-1] == sum)
                return true;
            if(sum<0)
                return false;
            if(sum<arr[n-1])
                return existsSum(arr, n-1,sum);
            return existsSum(arr, n-1, sum-arr[n-1])  || existsSum(arr, n-1,sum)  ;
        }

这很好用。但是,一旦我更改了这样的最后一行代码

    public static boolean existsSum(int[] arr, int n, int sum){
            if(sum==0)
                return true;
            if(n<=0)
                return false;
            if(arr[n-1] == sum)
                return true;
            if(sum<0)
                return false;
            if(sum<arr[n-1])
                return existsSum(arr, n-1,sum);
            return existsSum(arr, n-1,sum) || existsSum(arr, n-1, sum-arr[n-1])  ;
        }

已超过时间限制。我不明白更改顺序对执行时间有什么影响。请帮忙。

2 个答案:

答案 0 :(得分:4)

请注意||短路,即a || b中的事实,如果a为真,则b不会被评估。

||的两个操作数之间的区别在于,existsSum(arr, n-1, sum-arr[n-1])将当前项“加”到总和的项目列表中,而existsSum(arr, n-1, sum)则不是。

在第一个代码段中,如果existsSum(arr, n-1, sum-arr[n-1])为true,则甚至不会调用existsSum(arr, n-1, sum)。想象一下,我用数组[1,2,3]和总和6来调用它。第一个操作数将在每次递归调用中返回true,并且不需要评估第二个操作数。

类似地,在第二个代码段中,existsSum(arr, n-1, sum)首先运行,如果为true,则不调用existsSum(arr, n-1, sum-arr[n-1])。但是,existsSum(arr, n-1, sum)很少会自己返回真实的 。我的意思是,要使调用existsSum(arr, n-1, sum)返回true,值true必须来自对existsSum(arr, n-1, sum-arr[n-1])的递归调用。您可以通过分析不同的分支来验证这一点。 (两个返回true的分支是sum==0arr[n-1] == sum。希望您都同意这两种情况很少见),这意味着回溯(即调用existsSum(arr, n-1, sum-arr[n-1]))肯定会发生existsSum(arr, n-1, sum)


在最坏的情况下,这两个代码段是相同的。

答案 1 :(得分:0)

这应该是O(n)

public static boolean sumExists(int [] in, int sum) {
    //You might be able to get away with just sorting the values and not copying it.
    int [] input = Arrays.copyOf(in, in.length);
    Arrays.sort(input);
    int currentSum = 0;
    int startIdx = 0;
    for (int i = 0; i < input.length; i++) {
        if (currentSum > sum) {
            while (currentSum > sum && startIdx < i) {
                currentSum -= input[startIdx++];
            }
        }

        if (currentSum == sum) {
            return true;
        } 
        currentSum += input[i];
    }
    return false;
}
相关问题