Given n distinct positive integers, integer k (k <= n) and a number target.面試
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
.優化
這是sum一系列問題中的終極版本,即求給出的n個數字中,取其中k個數字,最終和爲target的組合有多少。spa
注意這題問的是有多少,並非要求給出全部的符合條件的k個數組的所有組合。按照前面的2 sum, 3sum, 4sum等題推理若是採用排序加雙指針夾逼的方法,複雜度是O(n^(k-1))的,若是採用4sum這種利用2sum hashmap的作法,則最優的複雜度爲有下降,可是4sum這種已經很複雜,對於更大的k爲偶數的狀況,會變得特別複雜。以上分析能夠看出DP是這時候的好選擇。指針
首先看這題自己的描述,n個取k個,組成和爲target的狀況,其實看描述很是像揹包問題,容量是這裏的target,可是揹包問題自己不要求知道一共是多少個物體組成,且不須要知道方案數,因此二維的DP沒法解決。咱們能夠定義3維的DP狀態:f[i][j][t]即前i個字母中取出j個能組成和爲t的狀況的種數。code
定義轉換狀態:f[i][j][t] = f[i-1][j][t] + f[i-1][j-1][t-nums[i-1]]和揹包問題同樣,咱們須要對取不取第i 個數字作一個判斷。blog
初始化,這個是最tricky的地方,究竟如何初始化纔對。首先數組中的全部的數字都是正數,且都不相同。因此f[i][1][A[i-1]]應該都是1. f[i][1][A[j]] = f[i-1][1][A[i]]+f[i-1][0][0], f[i-1][1][A[i]]確定是0,因此f[i-1][0][0]的值是1.能夠先進行初始化。排序
最後的結果是f[n][k][target].複雜度爲O(k*n*target).上述空間複雜度能夠採用滾動數組優化爲二維的(在n這一維度進行優化)。get
代碼以下:hash
class Solution: """ @param A: An integer array. @param k: a positive integer (k <= length(A)) @param target: integer @return an integer """ def kSum(self, A, k, target): n = len(A) dp = [[[0] * (target+1) for i in xrange(k+1)] for j in xrange(n+1)] for i in xrange(0, n+1): dp[i][0][0] = 1 for i in xrange(1, n+1): for j in xrange(1, min(k+1,i+1)): #j的範圍必定要注意 for t in xrange(1, target+1): if t < A[i-1]: dp[i][j][t] = dp[i-1][j][t] else: dp[i][j][t] = dp[i-1][j][t] + dp[i-1][j-1][t-A[i-1]] return dp[n][k][target]
這題三維的滾動數組優化比較困難,嘗試了幾回都有問題。後序再說。
這題難度比較高,面試中出現的機率比較低,但仍然是一道不錯的DP題。