Given n distinct positive integers, integer k (k <= n) and a number target.github
Find k numbers where sum is target. Calculate how many solutions there are?面試
Given [1,2,3,4], k=2, target=5. There are 2 solutions:算法
[1,4] and [2,3], return 2.ide
if (j == 0 && t == 0) {
// select 0 number from i to the target: 0
D[i][j][t] = 1;
}oop
1. 狀態表達式:優化
D[i][j][t] = D[i - 1][j][t];
if (t - A[i - 1] >= 0) {
D[i][j][t] += D[i - 1][j - 1][t - A[i - 1]];
}spa
意思就是:3d
(1)咱們能夠把當前A[i - 1]這個值包括進來,因此須要加上D[i - 1][j - 1][t - A[i - 1]](前提是t - A[i - 1]要大於0)
(2)咱們能夠不選擇A[i - 1]這個值,這種狀況就是D[i - 1][j][t],也就是說直接在前i-1個值裏選擇一些值加到target.
代碼:
1 /** 2 * @param A: an integer array. 3 * @param k: a positive integer (k <= length(A)) 4 * @param target: a integer 5 * @return an integer 6 */ 7 public int kSum1(int A[], int k, int target) { 8 // write your code here 9 if (target < 0) { 10 return 0; 11 } 12 13 int len = A.length; 14 15 int[][][] D = new int[len + 1][k + 1][target + 1]; 16 17 for (int i = 0; i <= len; i++) { 18 for (int j = 0; j <= k; j++) { 19 for (int t = 0; t <= target; t++) { 20 if (j == 0 && t == 0) { 21 // select 0 number from i to the target: 0 22 D[i][j][t] = 1; 23 } else if (!(i == 0 || j == 0 || t == 0)) { 24 D[i][j][t] = D[i - 1][j][t]; 25 if (t - A[i - 1] >= 0) { 26 D[i][j][t] += D[i - 1][j - 1][t - A[i - 1]]; 27 } 28 } 29 } 30 } 31 } 32 33 return D[len][k][target]; 34 }
咱們能夠把最外層的Matrix能夠省去。
這裏最優美的地方,在於咱們把target做爲外層循環,而且從右往左計算。這裏的緣由是:
D[i][j][t] += D[i - 1][j - 1][t - A[i - 1]];
這個表達式說明D[i][j][t]是把上一級i的結果累加過來。這裏咱們省去了i這一級,也就是說在D[j][t]這個表裏就地累加。並且t - A[i - 1]小於t。
在如下圖表示就是說D[j][t]是來自於上一行的在t左邊的這些值中挑一些加起來。
因此咱們就必須從右往左逐列計算來避免重複的累加。
1. 若是你從左往右按列計算,每一列會被重複地加總,就會有重複計算。咱們能夠想象一下,len = 0爲上表,len = 1爲下表。
如今咱們只有一個表,就是下面這個(由於第一個維度被取消了),如今若是你從左往右計算,被sum的區域會被填掉,覆蓋
len = 0 那張表留下的值,下一個值的計算就不會準確了。
2. 或者若是你逐行計算,也是不能夠的。由於你也是把生成D[j][t](在圖裏寫的是D[i][j])的被sum的區域覆蓋,也會形成結果不許確。
3. 因此,只要咱們逐列計算,而且順序是從右往左,即便咱們只有一個二維表,咱們的被sum區域也能夠保持潔淨,從空間角度來想,
就至關於從len=0那張表中取值。
總結:這種思惟方式可能在面試裏很難遇到,不過,能夠開拓咱們思惟,這裏一樣是動規時若是取得上一級的值的問題,而且它考慮了省
去一級,就地利用二維空間的值,那麼就要考慮咱們上一級的舊錶不要被覆蓋。能夠在大腦中構思一個三維空間,一個三維表由多個二維
表構成,若是把它們用一個表來作,再思考一下便可。
1 // 2 dimension 2 public int kSum(int A[], int k, int target) { 3 // write your code here 4 if (target < 0) { 5 return 0; 6 } 7 8 int len = A.length; 9 10 // D[i][j]: k = i, target j, the solution. 11 int[][] D = new int[k + 1][target + 1]; 12 13 // only one solution for the empty set. 14 D[0][0] = 1; 15 for (int i = 1; i <= len; i++) { 16 for (int t = target; t > 0; t--) { 17 for (int j = 1; j <= k; j++) { 18 if (t - A[i - 1] >= 0) { 19 D[j][t] += D[j - 1][t - A[i - 1]]; 20 } 21 } 22 } 23 } 24 25 return D[k][target]; 26 }
https://github.com/yuzhangcmu/LeetCode/blob/master/lintcode/dp/KSum.java