K Sum
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的组合有多少。
注意这题问的是有多少,并不是要求给出所有的符合条件的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的情况的种数。
定义转换状态:f[i][j][t] = f[i-1][j][t] + f[i-1][j-1][t-nums[i-1]]和背包问题一样,我们需要对取不取第i 个数字做一个判断。
初始化,这个是最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这一维度进行优化)。
代码如下:
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题。
posted on 2016-06-29 11:37 Sheryl Wang 阅读(369) 评论(0) 编辑 收藏 举报