我嘗試從下面提供的Codility中了解一個問題的解決方案,對于給定的具有N個整數的數組A和來自集合{?1,1}的N個整數的序列S,我們定義val(A,S)如下:val(A, S) = |sum{ A[i]*S[i] for i = 0..N?1 }|(假設零個元素的總和等于零。)對于給定的數組A,我們正在尋找使val(A,S)最小的序列S。編寫一個函數:class Solution { public int solution(int[] A); }在給定N個整數的數組A的情況下,對于集合{-1,1}中N個整數的所有可能序列S,從val(A,S)的所有可能值中計算val(A,S)的最小值。例如,給定數組: A[0] = 1 A[1] = 5 A[2] = 2 A[3] = -2您的函數應返回0,因為對于S = [?1,1,--1,1],val(A,S)= 0,這是可能的最小值。假使,假設:N is an integer within the range [0..20,000];each element of array A is an integer within the range [?100..100].Complexity:預期的最壞情況時間復雜度為O(N * max(abs(A))2); 預期的最壞情況下的空間復雜度為O(N + sum(abs(A)))(不計算輸入參數所需的存儲空間)。我有最近幾個小時想要了解的解決方案。public static int solution(int[] A) { int N = A.length; int sum = 0; int max = 0; for (int i = 0; i < N; i++) { A[i] = Math.abs(A[i]); sum += A[i]; max = Math.max(A[i], max); } int[] counts = new int[max + 1]; for (int i = 0; i < N; i++) { counts[A[i]] += 1; } int[] Total = new int[sum + 1]; Arrays.fill(Total, -1); Total[0] = 0; // Segment I for (int i = 1; i <= max; i++) { if (counts[i] > 0) { for (int j = 0; j <= sum; j++) { // j th index is zero or positive if (Total[j] >= 0) { Total[j] = counts[i]; } // (i-j) th index is positive else if ((j - i) >= 0 && Total[j - i] > 0) { Total[j] = Total[j - i] - 1; } } } }如果任何人都可以解釋循環的最后兩個部分中發生了什么,這將非常有幫助。我只想在幾行文字中找到一個簡短的解釋。
1 回答

慕村225694
TA貢獻1880條經驗 獲得超4個贊
為了使總和具有必需的屬性,可以找到總和盡可能接近總和一半的數組A的子集。
這是一種眾所周知的方法 subset sum problem
,可以通過動態編程方法解決,方法是使用尺寸對應于總和的附加數組(請注意數組Total
)。
請注意,問題的解決方案僅處理正數,因此您必須對其進行修改以使用負數(例如您的示例A[3] = -2
)。
此代碼使數組total
的長度變長,sum+1
并保存array中每個值的計數counts
。
在第一階段,代碼將所有可能總和的非整數項填充到總表中。考慮簡單的set value:count (2:3; 3:2)
。
第一輪以值3,2,1,0填充條目0,2,4,6。第二輪將所有非負條目更改為三分之二,并
從非負條目構建鏈的遞減序列(例如4--> 4+3 ->4+6
)。在那之后,我們得到了總數組,[2,-1,2,1,2,1,2,1,0,1,0,-1,0]
其中負條目(不可能的總和)為1,11。請注意,這種方法不存儲信息-使用了哪些項目來產生所有可能的總和,因此您必須進行更多的修改。
添加回答
舉報
0/150
提交
取消