簡體   English   中英

迭代和遞歸解決方案的時間復雜度

[英]Time complexity on iterative and recursive solution

我正在嘗試解決以下問題: 編程問題

我覺得我已經給了很多想法,嘗試了很多東西。 我設法解決了這個問題,並產生了正確的值,但是問題是時間效率不夠高。 它完成了Kattis測試中的2個,但由於超過了1秒的時間限制而未能完成3個測試。 恐怕我沒有辦法看到他們測試的輸入是什么。

我從一個遞歸解決方案開始,並完成了這一過程。 但是后來我意識到這不夠省時,因此我嘗試改用迭代解決方案。

我從讀取輸入開始,然后將其添加到ArrayList中。 然后,我將目標為1000的以下方法調用。

public static int getCorrectWeight(List<Integer> platesArr, int target) {
    /* Creates two lists, one for storing completed values after each iteration,
    one for storing new values during iteration. */
    List<Integer> vals = new ArrayList<>();
    List<Integer> newVals = new ArrayList<>();

    // Inserts 0 as a first value so that we can start the first iteration.
    int best = 0;
    vals.add(best);

    for(int i=0; i < platesArr.size(); i++) {
        for(int j=0; j < vals.size(); j++) {
            int newVal = vals.get(j) + platesArr.get(i);
            if (newVal <= target) {
                newVals.add(newVal);
                if (newVal > best) {
                    best = newVal;
                }
            } else if ((Math.abs(target-newVal) < Math.abs(target-best)) || (Math.abs(target-newVal) == Math.abs(target-best) && newVal > best)) {
                best = newVal;
            }
        }
        vals.addAll(newVals);
    }
    return best;
}

我的問題是,對於減少大量數據,我是否可以通過某種方法來減少時間復雜度?

主要的問題是大小valsnewVals可以非常快速地增長,因為每個迭代可以增加一倍它們的大小。 您只需要存儲1000個左右的值即可管理。 您在限制值,但是因為它們存儲在ArrayList ,所以最終會有很多重復的值。

相反,如果您使用了HashSet ,那么它將HashSet提高效率。

您僅需要存儲大小為2001(0到2000)的DP表,讓dp[i]表示是否可以形成i kg的權重。 如果權重超出數組范圍,請忽略它。 例如:

dp[0] = 1;      
for (int i = 0; i < values.size();  i++){
    for (int j = 2000; j >= values[i]; j--){  
        dp[j] = max(dp[j],dp[j-values[i]);
    }
}

在這里, values是存儲所有原始權重的位置。 dp[0]外,所有dp值均應設置為0。

然后,檢查是否有可能達到1000。 如果不是,請檢查999和1001,依此類推。 這應該以O(1000n + 2000)時間運行,因為n最多為1000,所以應該及時運行。

順便說一句,這是一種改進的背包算法,您可能需要查找其他一些變體。

如果您對這種類型的問題過於籠統,則可能會認為您必須檢查所有可能的輸入組合(每個權重都可以包括或排除),為您提供2 n種組合以測試是否有n種輸入。 但是,這不是重點。 相反,這里的關鍵是所有權重都是整數,目標是1000。

讓我們先檢查極端情況,因為這限制了搜索空間。

如果所有權重均> = 1000,則選擇最小的權重。

如果至少有一個權重<1000,則總是比任何權重> = 2000更好,因此出於組合目的,您可以忽略任何權重> = 1000。

然后,應用動態編程。 保留前k個輸入的所有組合的集合(從其他海報中獲得HashSet作為建議,但BitSet更好,因為其最大值很小),並通過將所有先前的解決方案與k + 1組合來增加k的輸入。

考慮完所有可能性后,只需搜索位向量以獲得最佳響應。

static int count() {
    int[] weights = new int[]{900, 500, 498, 4};

    // Check for corner case to limit search later
    int min = Integer.MAX_VALUE;
    for (int weight : weights) min = Math.min(min, weight);
    if (min >= 1000) {
        return min;
    }        
    // Get all interesting combinations
    BitSet combos = new BitSet();
    for (int weight : weights) {  
        if (weight < 1000) {
            for (int t = combos.previousSetBit(2000 - weight) ; t >= 0; t = combos.previousSetBit(t-1)) {
                combos.set(weight + t);
            }
            combos.set(weight);
        }
    }
    // Pick best combo
    for (int distance = 0; distance <= 1000; distance++) {
        if (combos.get(1000 + distance)) {
            return 1000 + distance;
        }
        if (combos.get(1000 - distance)) {
            return 1000 - distance;
        }
    }
    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM