簡體   English   中英

javascript - 找到在特定限制下給出最大總和的子集(子集總和)

[英]javascript - find subset that gives maximum sum under a certain limit (subset sum )

我有一個包含一些整數值的數組,我需要獲取它們的一個子集,該子集為我提供低於給定值的最大總和。
所以假設我有這個數組:

[40, 138, 29, 450]

我想得到這個數組的一個子集,它使總和最大化,但低於用戶給定的限制,比如 250。在這種情況下,它應該返回 [139, 40, 29]。
我看了一下這個問題和相關的答案,並嘗試使用給出的代碼,但我不是很理解。 無論如何,我已經嘗試過,將最小值設置為 0,將最大值設置為給定的限制,但它不斷返回“5”,這是不正確的,因為限制類似於 300,並且我的數組中的數字都超過了 50。
我找不到任何可以幫助我的東西,所以我問是否有人可以給我一些代碼或偽代碼來了解如何做到這一點。

基本上,您可以將索引處的元素添加到臨時數組中。 然后檢查索引是否達到數組的長度,或者如果總和大於所需的總和,則檢查總和並將temp數組添加到結果集中。

繼續進行,直到訪問所有索引。

 function getCombinations(array, sum) { function add(a, b) { return a + b; } function fork(i, t) { var r = (result[0] || []).reduce(add, 0), s = t.reduce(add, 0); if (i === array.length || s > sum) { if (s <= sum && t.length && r <= s) { if (r < s) { result = []; } result.push(t); } return; } fork(i + 1, t.concat([array[i]])); fork(i + 1, t); } var result = []; fork(0, []); return result; } console.log(getCombinations([40, 138, 29, 450], 250)); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

快速緊湊的解決方案:

function maxSum(input, limit) {
    const sums = {};
    let max = 0;

    const collectSums = (n, i, values) => {
        for (; i < input.length; i++) {
            const sum = n + input[i];
            if (sum <= limit) {
                values.push(input[i]);
                if (sum >= max && values.length > 1) {
                    max = sum;
                    sums[max] = values.slice(); // https://jsperf.com/copying-an-array
                }
                collectSums(sum, i + 1, values);
            }
        }
        values.pop();
    };

    collectSums(0, 0, []);

    return sums[max] || [];
}

除了必要的輸入迭代之外,該解決方案還試圖通過不使用昂貴的陣列操作來降低復雜性。 只需復制已找到的子集以跟蹤可能的組合。 盡管如此,可能還有更多聰明的解決方案可以提高性能。

該方法將返回最后找到的組合,這意味着具有不同順序的相同值的兩個輸入列表可能會產生不同的結果:

maxSum([1, 4, 200, 5], 205) == [200, 5];
maxSum([5, 200, 1, 4], 205) == [200, 1, 4];

如果您想要所有可能的組合,請替換此行:

sums[max] = values.slice(); // https://jsperf.com/copying-an-array

有了這個:

sums[max] = sums[max] || [];
sums[max].push(values.slice());

然后返回所有組合:

maxSum([1, 4, 200, 5], 205) == [[1, 4, 200], [200, 5]];

但請注意,這將始終返回一個數組數組,即使只有一種可能性:

maxSum([40, 138, 29, 450], 250) == [[40, 138, 29]];

這是一個強力解決方案。 首先,我們從原始數組中獲取每個可能的值組合,獲取它們的總和,並查看哪些值得到我們最高值而不會溢出給定的最大值。

 var ary = [40, 138, 29, 450]; // Function to construct a power set. A power set is just the set of // all possible subsets of some given set. function makePowerSet(ary) { powerSet = []; for (let ps = 1; ps <= Math.pow(2, ary.length); ps++) { subset = []; for (let i = 0; i < ary.length; i++) { if (ps & Math.pow(2, i)) subset.push(ary[i]); } powerSet.push(subset); } return powerSet; } // Function to calculate the sum of an array. function getSum(ary) { return ary.reduce((sum, cur) => { return sum + cur; }, 0); } function getSubsetBelow(val, ary) { let bestSoFar; let bestSoFarSum = 0; for (let subset of makePowerSet(ary)) { const sum = getSum(subset); if (sum > val) continue; if (sum > bestSoFarSum) { bestSoFar = subset; bestSoFarSum = sum; } } console.log("Got a best sum value of", bestSoFarSum, "with the subset", bestSoFar); } getSubsetBelow(250, ary) 

這看起來非常類似於背包問題 ,這是NP難的,所以我不知道你是否能夠找到一個有效的算法。 但是,對於我在這里所寫的內容肯定會有一些優化,例如,陣列中任何已超過限制的元素都不能成為解決方案的一部分(消除450的簡單方法)。

#求數組元素的緊湊子序列的最大和。

import sys
def solution(A):
 max_ending = max_slice = -sys.maxsize
 if(len(A)==1):
     return A[0]
 else:
     for a in A:
         max_ending =max(a,max_ending + a)
         max_slice = max(max_slice, max_ending)
     return max_slice

暫無
暫無

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

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