lintcode: k Sum 解題報告

13%
Accepted

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?面試

Example

Given [1,2,3,4], k=2, target=5. There are 2 solutions:算法

[1,4] and [2,3], return 2.ide

Tags  Expand 
 

SOLUTION 1:

唉媽,主頁君作這題搞了2,3小時差點吐血。不過,作出來仍是很爽嘀!
取自黃老師(九章算法)的思想:
 
 
 
 
 
後面的優化主頁君沒有管。 F[0][0][0]表示在一個空集中找出0個數,target爲0,則有1個解,就是什麼也不挑嘛!
其實應該這樣寫,也就是說,找0個數,目標爲0,則必定是有1個解:

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     }
View Code

 

SOLUTION 2:

咱們能夠把最外層的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     }
View Code

 

https://github.com/yuzhangcmu/LeetCode/blob/master/lintcode/dp/KSum.java

相關文章
相關標籤/搜索