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题。