7. 尋找和為定值的任意多個數

一、尋找和為定值的兩個數

算法思想:

  1. 排序,然后兩端掃描。時間復雜度O(nlogn+n) 空間復雜度O(1)
  2. 散列映射,先確定其中一個數,再判斷另一個是否存在。時間復雜度O(1),空間復雜度O(n)

算法實現

#include <iostream>
#include <algorithm>
#include <fstream>

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 <iostream>
#include <fstream>

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];
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容