3 回答

TA貢獻1831條經(jīng)驗 獲得超10個贊
def total_subsets_matching_sum(numbers, sum):
array = [1] + [0] * (sum)
for current_number in numbers:
for num in xrange(sum - current_number, -1, -1):
if array[num]:
array[num + current_number] += array[num]
return array[sum]
assert(total_subsets_matching_sum(range(1, 10), 9) == 8)
assert(total_subsets_matching_sum({1, 3, 2, 5, 4, 9}, 9) == 4)
說明
這是經(jīng)典問題之一。這個想法是用當前數(shù)量找到可能的總和數(shù)量。確實,只有一種方法可以將總和設(shè)為0。一開始,我們只有一個數(shù)字。我們從目標(解決方案中的變量最大值)開始,然后減去該數(shù)字。如果有可能獲得該數(shù)字的和(與該數(shù)字對應(yīng)的數(shù)組元素不為零),則將其添加到與當前數(shù)字對應(yīng)的數(shù)組元素中。該程序?qū)⒏菀桌斫膺@種方式
for current_number in numbers:
for num in xrange(sum, current_number - 1, -1):
if array[num - current_number]:
array[num] += array[num - current_number]
當數(shù)字為1時,只有一種方法可以得出總和1(1-1變?yōu)?且對應(yīng)于0的元素為1)。因此,數(shù)組將像這樣(記住元素零將具有1)
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
現(xiàn)在,第二個數(shù)字為2。我們開始從9中減去2,并且它是無效的(由于7的數(shù)組元素為零,因此我們跳過了這一點),直到3為止。當其3、3-2為1且數(shù)組元素為對應(yīng)于1的是1,然后將其添加到3的數(shù)組元素中。當其2、2-2變?yōu)?時,我們將對應(yīng)于0的值添加到2的數(shù)組元素中。在此迭代之后,數(shù)組看起來像這樣
[1, 1, 1, 1, 0, 0, 0, 0, 0, 0]
我們一直這樣做,直到每次迭代后處理所有數(shù)字和數(shù)組都像這樣
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
[1, 1, 1, 1, 0, 0, 0, 0, 0, 0]
[1, 1, 1, 2, 1, 1, 1, 0, 0, 0]
[1, 1, 1, 2, 2, 2, 2, 2, 1, 1]
[1, 1, 1, 2, 2, 3, 3, 3, 3, 3]
[1, 1, 1, 2, 2, 3, 4, 4, 4, 5]
[1, 1, 1, 2, 2, 3, 4, 5, 5, 6]
[1, 1, 1, 2, 2, 3, 4, 5, 6, 7]
[1, 1, 1, 2, 2, 3, 4, 5, 6, 8]
在最后一次迭代之后,我們將考慮所有數(shù)字,并且獲得目標的方法數(shù)量將是與目標值相對應(yīng)的數(shù)組元素。在我們的例子中,最后一次迭代后的Array [9]為8。

TA貢獻1891條經(jīng)驗 獲得超3個贊
您可以使用動態(tài)編程。算法復(fù)雜度為O(Sum * N),并使用O(Sum)內(nèi)存。
這是我在C#中的實現(xiàn):
private static int GetmNumberOfSubsets(int[] numbers, int sum)
{
int[] dp = new int[sum + 1];
dp[0] = 1;
int currentSum =0;
for (int i = 0; i < numbers.Length; i++)
{
currentSum += numbers[i];
for (int j = Math.Min(sum, currentSum); j >= numbers[i]; j--)
dp[j] += dp[j - numbers[i]];
}
return dp[sum];
}
注意:由于子集數(shù)可能具有2 ^ N的值,因此很容易會溢出int類型。
算法僅適用于正數(shù)。
添加回答
舉報