繁体   English   中英

如何计算此递归函数的最坏情况时间复杂度?

[英]How would I calculate the worst case time complexity of this recursive function?

我不相信这是有效的。 我正在尝试创建一个更快的实现(最好是二进制搜索或者使用Sets),但是现在这就是我所处的位置。 我不确定它是否相关,但我创建了一个计数变量,只是为了查看调用该方法的次数。 它达到了577次。

这是“子集和”算法,其中我必须显示添加到目标总和的所有子集,在本例中为3165.没有具体说明这个问题是算法,但我意识到它确实是相同的概念。

我的问题是我如何知道这个程序的效率如何,方法调用指标是什么?

public class SubsetSumAlgorithm {

    static int count = 0;

    public static void main(String[] args) {

        int[] array = {26, 39, 104, 195, 403, 504, 793, 995, 1156, 1673};

        System.out.println("COLLECTIONS IN ARRAY THAT ADD TO 3165: ");
        findCollections(array, 0, 0, 3165, "");
        System.out.println("Method called " + count + " times.");//method calls
    }

    public static void findCollections(int[] array, int index, int currentPosition, int sum, String collection) {

        count++; //<---COUNTING THE METHOD CALLS HERE

        if (array.length < index || currentPosition > sum) {
            return;
        }
        //if sum is found, add to subset
        for (int i = index; i < array.length; i++) {
            if (currentPosition + array[i] == sum) {
                System.out.println(collection + " " + array[i]);
            }
            //otherwise, call the method again
            else if (currentPosition + array[i] < sum) {//recursive call
                findCollections(array, i + 1, currentPosition + array[i], sum, collection + " " + array[i]);
            }
        }
    }
}

这是输出:

COLLECTIONS IN ARRAY THAT ADD TO 3165: 
26 195 793 995 1156
195 504 793 1673
Method called 577 times.

我的问题是我如何知道这个程序的效率如何,方法调用指标是什么?

导出算法的渐近运行时间的唯一方法是实际上弄脏你的手并手动完成 有了这样说,尝试在算法运行时跟踪方法调用并不是一种可靠合理的方法来推导算法的运行时。

要开始尝试计算算法的运行速度或速度,我们可以从分析每行的运行时间得出重现:

1    public static void findCollections(int[] array, int index, int currentPosition, int sum, String collection) {
2        if(array.length < index || currentPosition > sum)
3            return;
4        for(int i = index; i < array.length; i++) {
5            if(currentPosition + array[i] == sum) {
6                System.out.println(collection + " " + array[i]);
7            }
8            else if(currentPosition + array[i] < sum) {
9                findCollections(array, i + 1, currentPosition + array[i], sum, collection + " " + array[i]);
10           }
11       }
12   }

...

1    -
2    1
3    1
4    n+1
5    n
6    n
7    -
8    n
9    n*T(n-1)
10   -
11   -
12   -

我们分析了每一行,我们可以推导出复发:

    T(n) = n*T(n-1) + 4n + 3
 => T(n) = n*T(n-1) + 4n + Θ(1)
 => T(n) = n*T(n-1) + 4n

由于我们不能使用主定理 ,并且尝试递归树会非常混乱并且非常快速地混淆这种特定的重复,我们可以使用替换方法来解决这种重复。 我们将初始猜测设置为2^n因为它看起来像它可能是指数的:


上界O(2^n)


这意味着

T(n) ≤ c * 2^n

如果这个命题成立,这意味着我们也知道这一点

T(n-1) ≤ c * 2^(n-1)

因此,我们现在可以写下我们的重复并尝试证明我们的猜测:

    c * 2^n ≥ n * (c * 2^(n-1)) + 4n
 => c * 2^n ≥ c * n * 2^(n-1) + 4n

这适用于所有n > 0 | c = 1 n > 0 | c = 1 ,因此T(n) = O(2^n)


下界Ω(2^n)


这意味着

T(n) ≥ c * 2^n

如果这个命题成立,这意味着我们也知道这一点

T(n-1) ≥ c * 2^(n-1)

因此,我们现在可以写下我们的重复并尝试证明我们的猜测:

    c * 2^n ≤ n * (c * 2^(n-1)) + 4n
 => c * 2^n ≤ c * n * 2^(n-1) + 4n

这适用于所有n > 0 | c = 5000 n > 0 | c = 5000 ,因此T(n) = Ω(2^n)


结论Θ(2^n)


由于我们已经证明该算法是O(2^n) Ω(2^n) ,因此根据定义它也是Θ(2^n) 所以基本上,你的算法的时间复杂度是Θ(2^n) ,这是非常慢的,因为它是指数的。

如果您想通过实验找到趋势,则调用Method的次数是一个不错的指标。 您需要使用不同的输入多次运行该函数,收集数据,绘制图形并找到最佳拟合曲线......这将假设对findCollections调用与执行所需的时间直接相关。 然而,在这里找到最坏的情况并不太难。 您只需要考虑哪些输入变量会导致执行时间最长。

在这种情况下,如果sum变量大于整个集合的总和,您将看到最差的执行(最多的递归)。 如果这个条件为真,那么下面的方法将等同于你的方法:

public static void findCollections(int[] array, int index, int currentPosition, int sum, String collection) {
    for(int i = index; i < array.length; i++) {
        findCollections(array, i + 1, currentPosition + array[i], sum, collection + " " + array[i]);
    }
}

这里很容易看出,这将循环遍历所有可能的array子集。 这使得您的解决方案为O(2^n) ,其中n是array的大小

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM