簡體   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