【Lintcode】89. k Sum

题目地址:

https://www.lintcode.com/problem/k-sum/description

给定一个正整数数组 A A A,再给定一个正整数 s s s和一个目标值 t t t,问从这个数组中有多少种方法取出 s s s个数其和为 t t t

思路是动态规划。设 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]为从数组 A A A的前 i i i个数里取出 j j j个数,其和为 k k k的方案数,其中允许从前 0 0 0个数里取,也允许取 0 0 0个数。那么显然,取 0 0 0个数和为 0 0 0的方案数是 1 1 1种,所以 f [ i ] [ 0 ] [ 0 ] = 1 f[i][0][0]=1 f[i][0][0]=1。接下来我们考虑递推关系。对于从前 i i i个数里取出 j j j个数和为 k k k的方案,我们可以分为两部分:
1、该方案不包含 A [ i − 1 ] A[i-1] A[i1],那么这种情况的方案总数为 f [ i − 1 ] [ j ] [ k ] f[i-1][j][k] f[i1][j][k]
2、该方案包含 A [ i − 1 ] A[i-1] A[i1],那么这种情况的方案总数为 f [ i − 1 ] [ j − 1 ] [ k − A [ i − 1 ] ] f[i-1][j-1][k-A[i-1]] f[i1][j1][kA[i1]],而这种情况的方案只在 k ≥ A [ i − 1 ] k\ge A[i-1] kA[i1]时存在。
所以 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]就是上面两种方案数的总和,即: f [ i ] [ j ] [ k ] = f [ i − 1 ] [ j ] [ k ] + f [ i − 1 ] [ j − 1 ] [ k − A [ i − 1 ] ] f[i][j][k]=f[i-1][j][k]+f[i-1][j-1][k-A[i-1]] f[i][j][k]=f[i1][j][k]+f[i1][j1][kA[i1]]最后只需要返回 f [ l A ] [ s ] [ t ] f[l_A][s][t] f[lA][s][t]。初始条件, ∀ i , f [ i ] [ 0 ] [ 0 ] = 1 \forall i, f[i][0][0]=1 i,f[i][0][0]=1 ∀ s > 0 , f [ 0 ] [ 0 ] [ s ] = 0 \forall s > 0,f[0][0][s]=0 s>0,f[0][0][s]=0。代码如下:

public class Solution {
    /**
     * @param A: An integer array
     * @param k: A positive integer (k <= length(A))
     * @param target: An integer
     * @return: An integer
     */
    public int kSum(int[] A, int k, int target) {
        // write your code here
        // 判空
        if (A == null || A.length == 0) {
            return 0;
        }
        
        int[][][] dp = new int[A.length + 1][k + 1][target + 1];
        for (int i = 0; i <= A.length; i++) {
            dp[i][0][0] = 1;
        }
    
        for (int i = 0; i <= A.length; i++) {
            for (int j = 0; j <= k; j++) {
                for (int l = 0; l <= target; l++) {
                	// 前i个物品里选j个,如果i < j那一定选不出来,跳过
                	if (i < j) {
                		continue;
                	}
                	
                    if (i > 0) {
                        dp[i][j][l] = dp[i - 1][j][l];
                    }
                    
                    if (i > 0 && j > 0 && l >= A[i - 1]) {
                        dp[i][j][l] += dp[i - 1][j - 1][l - A[i - 1]];
                    }
                }
            }
        }
        
        return dp[A.length][k][target];
    }
}

时空复杂度 O ( n k t ) O(nkt) O(nkt),其中 n n n是数组长度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值