九章算法 | Google面试题:K数之和

给定 n 个不同的正整数,整数 kk <= n)以及一个目标数字 target。 

在这 n 个数里面找出 k 个数,使得这 k 个数的和等于目标数字,求问有多少种方案?

在线评测地址:LintCode 领扣

样例1

输入:
List = [1,2,3,4]
k = 2
target = 5
输出: 2
说明: 1 + 4 = 2 + 3 = 5 

样例2

输入:
List = [1,2,3,4,5]
k = 3
target = 6
输出: 1
说明: 只有这一种方案。 1 + 2 + 3 = 6 

算法:dp

如果没有k的约束。我们可以发现,这题就可以转化为背包问题。利用n个正整数达到目标target。那么有了k的约束之后,我们需要用额外的一维来维护使用的数字。所以约定状态如下,用dp[i][j][k]表示前ii个数里选j个和为k的方案数。

  • 假定dp[i][j][k]之前的方案数都已知,考虑dp[i][j][k]的情况。
  • dp[i][j][k]可以由dp[i−1][j−1][k−A[i−1]]的状态取​A[i-1]​得到。
  • dp[i][j][k]也可以由dp[i−1][j][k]直接得到,即不取​A[i-1]​。
  • 最后返回f[n][k][target]即可。

复杂度分析

  • 时间复杂度O(n∗k∗target)O(n∗k∗target)
  • 空间复杂度O(n∗k∗target)O(n∗k∗target)
    • 时间复杂度与空间复杂度是等价的。
    • 在这里,空间复杂度可以用滚动数组优化。
public class Solution {
      
      
    /**
     * @param A: an integer array.
     * @param k: a positive integer (k <= length(A))
     * @param target: a integer
     * @return an integer
     */
    public int  kSum(int A[], int k, int target) {
      
      
        int n = A.length;
        int[][][] f = new int[n + 1][k + 1][target + 1];
        for (int i = 0; i < n + 1; i++) {
      
      
            f[i][0][0] = 1;
        }
        for (int i = 1; i <= n; i++) {
      
      
            for (int j = 1; j <= k && j <= i; j++) {
      
      
                for (int t = 1; t <= target; t++) {
      
      
                    f[i][j][t] = 0;
                    if (t >= A[i - 1]) {
      
      
                        f[i][j][t] = f[i - 1][j - 1][t - A[i - 1]];
                    }
                    f[i][j][t] += f[i - 1][j][t];
                } // for t
            } // for j
        } // for i
        return f[n][k][target];
    }
} 

更多题解参考:九章算法

猜你喜欢

转载自blog.csdn.net/JiuZhang_ninechapter/article/details/109672109