7. 寻找和为定值的任意多个数

一、寻找和为定值的两个数

算法思想:

  1. 排序,然后两端扫描。时间复杂度O(nlogn+n) 空间复杂度O(1)
  2. 散列映射,先确定其中一个数,再判断另一个是否存在。时间复杂度O(1),空间复杂度O(n)

算法实现

#include 
#include 
#include 

using namespace std;

int main()
{
    ifstream cin("in.txt");

    int n, a[100], ans;

    while(cin >> n)
    {
        for(int i = 0; i < n; ++i)
            cin >> a[i];

        cin >> ans;

        sort(a, a+n);

        int i = 0, j = n-1;

        while(i < j)
        {
            if(a[i] + a[j] < ans)
                ++i;
            else if(a[i] + a[j] > ans)
                --j;
            else
            {
                cout << a[i] << " " << a[j] << endl;
                break;
            }
        } 
    }
}
二、扩展:寻找和为定值的任意多个数
1. 递归法

算法思想:考虑是否取第n个数,问题可以转化为前n-1个数和为sum-a[n-1]的问题,也可以转化为后n-1个数的求和问题。使用递归思想解决。

  • 如果取第n个数,即求得前n-1个数满足和为sum-a[n-1]的问题
  • 如果不取第n个数,即求得前n-1个数满足和为sum的问题
#include 
#include 

using namespace std;

int res[100], k = 0;

void sumOfKNumber(int * a, int n, int sum)
{
    if(n <= 0 || sum <= 0)
        return;

    if(k > 0)
    {
        if(sum == a[n-1])
        {
            for(int i = k-1; i >= 0; --i)
                cout << res[i] << "+";

            cout << a[n-1] << endl; //特别注意,输出时,该元素还未加入数组
        }
    }

    //考虑是否取第n个数
    res[k++] = a[n-1];
    sumOfKNumber(a, n-1, sum-a[n-1]);
    k--;

    sumOfKNumber(a, n-1, sum);
}

int main()
{
    ifstream cin("in.txt");

    int n, a[100], ans;

    while(cin >> n)
    {
        for(int i = 0; i < n; ++i)
            cin >> a[i];
        cin >> ans;

        sumOfKNumber(a, n, ans);
    }

    return 0;
}
三、k个和为定值的个数

题目:给出[1,2,3,4],k=2, target=5,[1,4] and [2,3]是2个符合要求的方案
地址:http://www.lintcode.com/zh-cn/problem/k-sum/
解析:dp[i][j][p] 表示从i个数中挑j个数和为p时的次数。
dp[0][0][0]表示在一个空集中找出0个数,target为0,则有1个解,就是什么也不挑嘛!
其实应该这样写,也就是说,找0个数,目标为0,则一定是有1个解:
if (j == 0 && p == 0) {
  // select 0 number from i to the target: 0
  D[i][j][p] = 1;
}

  1. 状态表达式:
D[i][j][p] = D[i - 1][j][p];  //不包含第i个元素
if (p - A[i - 1] >= 0) { //可以包含第i个元素
D[i][j][p] += D[i - 1][j - 1][t - A[i - 1]];
}

意思就是:

(1)我们可以把当前A[i - 1]这个值包括进来,所以需要加上D[i - 1][j - 1][t - A[i - 1]](前提是t - A[i - 1]要大于0)

(2)我们可以不选择A[i - 1]这个值,这种情况就是D[i - 1][j][t],也就是说直接在前i-1个值里选择一些值加到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) {
        // write your code here
        
        int len = A.length;
        int [][][] dp = new int[len+1][k+1][target+1];
        
        if(target < 0)
            return 0;
            
        for(int i = 0; i <= len; ++i)
            for(int j = 0; j <= k; ++j)
                for(int p = 0; p <= target; ++p)
                {
                    if(j == 0 && p == 0)
                        dp[i][j][p] = 1;
                    else if(i != 0 && j != 0 && p!= 0)
                    {
                        dp[i][j][p] = dp[i-1][j][p];
                        if(p >= A[i-1])
                            dp[i][j][p] += dp[i-1][j-1][p-A[i-1]];
                    }
                    
                }
                
        return dp[len][k][target];
    }
}

你可能感兴趣的:(7. 寻找和为定值的任意多个数)