2016-08-02 92 views

回答

6

您正在嘗試解決Partition Problem;即將整數分成兩個子集,其總和相同,並將正號分配給一個子集中的整數,將負號分配給另一個子集中的整數。

在您的特定問題中,您對整數數量和整數值都有一個下限。您可以使用包含/排除方法應用標準動態算法方法;即通過考慮這些整數中的最後一個未被使用(因此需要第一個總和爲i的整數的子集)以及它被使用的位置(一個子集)的情況來找到總計爲i的第一個整數的子集第一個n-1整數總和爲i - val(n))。

+0

雖然此鏈接可以回答這個問題,最好是在這裏有答案的主要部件,並提供鏈接以供參考。如果鏈接頁面更改,則僅鏈接答案可能會失效。 - [來自評論](/ review/low-quality-posts/13205501) – manetsus

+0

@manetsus - 答案的文字給出了要點,這是OP試圖回答的問題的名稱。在這種情況下,鏈接對回答問題沒有必要;它只是錦上添花。 – borrible

2

這裏有一個想法:

  1. 排序第2至第N個元素降(問題保持不變)。
  2. 反向構建累計和。 [1 4 3 2] => [10 9 5 2]獲得最高數字的上限,您仍然可以通過其餘整數達到上限。
  3. 使用反向累積和的界限進行修剪。

在Java:

// assuming the numbers are positive 
// (ignore operator when parsing, line.split("[ +-]+") will do) 
public static int canReach0(int[] numbers) { 
    sort(numbers, 1); // sort(array, offset) doesn't matter what algorithm 
        // for 300 elements and compared to the complexity of the rest 
    int[] revSum = new int[numbers.length]; 
    revSum[numbers.length - 1] = numbers[numbers.length - 1]; 
    for (int i = numbers.length - 2; i >= 0; i--) 
    revSum[i] = revSum[i + 1] + numbers[i]; 
    int sum = numbers[0]; 
    if (sum == revSum[1]) 
    return 0; 
    return solve(numbers, 1, sum, revSum); 
} 

private static int solve(int[] numbers, int index, int sum, int[] revSum) { 
    if (index == numbers.length - 1) 
    return -1; 
    int high = sum + numbers[index]; 
    if (high == revSum[index + 1] || 
     (high < revSum[index + 1] && solve(numbers, index + 1, high, revSum) == 0)) 
    return 0; 
    int low = sum - numbers[index]; 
    if (low == -revSum[index + 1] || 
     (low > -revSum[index + 1] && solve(numbers, index + 1, low, revSum) == 0)) 
    return 0; 
    return -1; 
} 
相關問題