/*************************************************************************
	> File Name: 163.cpp
	> Author: 
	> Mail: 
	> Created Time: 2015年11月11日 星期三 13时55分16秒
 ************************************************************************/

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

/*output the vector data*/
struct myclass{
    void operator() (int i){
        cout << i << " ";
    }  
}myobject;

/*recursion二分递归查找*/
int binary_search_recursion(const vector<int> &v, int low, int high, int goal)
{
    if (low <= high){
        int middle = (low + high) / 2;
        if (goal == v[middle])
            return middle;
        else if (goal > v[middle])
            binary_search_recursion(v, middle+1, high, goal);
        else
            binary_search_recursion(v, low, middle-1, goal);
    }
    else    
        return -1;
}

void input_data(int *n, int *m, vector<int> &k)
{
    int val;
    cout << "n = ";
    cin >> *n;
    cout << "m = ";
    cin >> *m;
    cout << "k = {";
    for (int i = 0; i < *n; i++){
        cin >> val;
        k.push_back(val);
        cin.get();
        cin.get();
    }
}
/*暴力枚举*/
void solve_1(int n, int m, const vector<int> &k)
{
    for (int a = 0; a < n; a++)
        for (int b = 0; b < n; b++)
            for (int c = 0; c < n; c++)
                 for (int d = 0; d < n; d++){
                     if (k[a] + k[b] + k[c] + k[d] == m){
                      
  cout << "Yes" << endl;
                        return;
                     }
                }

    cout << "No" << endl;
    return;
}

/*N^3*O(longN)*/
void solve_2(int n, int m, const vector<int> &k)
{

    for (int a = 0; a < n; a++)
        for (int b = 0; b < n; b++)
            for (int c = 0; c < n; c++){
                if (binary_search_recursion(k, 0, k.size()-1, m-k[a]-k[b]-k[c]) != -1){
                    cout << "Yes" << endl;
                    return;
                }
            }

    cout << "No" << endl;
    return;
}

/*N^2*O(longN)*/
void solve_3(int n, int m, const vector<int> &k)
{
    vector<int> k34;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            k34.push_back(k[i] + k[j]);

    sort(k34.begin(), k34.end());

    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++){
            if (binary_search_recursion(k34, 0, k34.size()-1, m-k[i]+k[j]) != -1){
                cout << "Yes" << endl;
                return;
            }
        }

    cout << "No" << endl;
    return;
}

int main()
{
    int n = 0, m = 0;
    vector<int> k;

    input_data(&n, &m, k);

    solve_1(n, m, k);

    sort(k.begin(), k.end());
    solve_2(n, m, k);

    solve_3(n, m, k);

    return 0;
}

第一种解法:枚举法,将四次的所有的可能取值相加,如果等于m,则输出Yes,否则输出No;这个解法很简单,四个嵌套的for循环很简单就可以实现;但是时间复杂度太高,O(N^4),如果N的值比较大,那么这个程序会很耗时间;

第二种解法:目的就是为了降低时间复杂度,所以只能对那四个for循环下手,所以思路------就是减少for循环的个数;
在最后一个for循环中判断k[a]+k[b]+k[c]+k[d] == m;其实也就是在这个数组中判断是不是存在k[d] == m-k[a]-k[b]-k[c];
所以最后一个循环就可以改变为对一个数值(m-k[a]-k[b]-k[c])进行查找,如果这里用普通的查找,时间复杂度是O(N),那么整体的时间复杂度是N^3O(N),那么时间复杂度没有下降;
所以用简单的二叉查找(如果要用二叉查找,那么必须要提前对数组进行排序,排序的时间复杂度为最差的是O(N^2)),二叉查找的时间复杂度是O(logN);那么该解决方法的总的时间复杂度是 O(N^2)+N^3O(logN),也就是N^3O(logN);

第三种解法:因为第二种的时间复杂度还是比较高;所以我们还要对其进行减小;但是入手处在哪里????当然还是for循环;
我们再减少一个for循环,让第二个for循环里面进行判断 m-k[a]+k[b] == k[c]+k[d];

所以我们必须提前将k[c]+k[d]所有的情况的取值存储在一个数组kk中(必须排序,时间复杂度为N^2O(logN)),在第二个for循环里面在数组kk中二叉查找m-k[a]+k[b],二叉查找的时间复杂度是O(logN);

所以整体的时间复杂度是N^2O(logN)+N^2O(logN),也就是N^2O(logN);等于排序的时间复杂度加上for循环的时间复杂度;

posted on 2015-11-11 16:46  Linux-ever  阅读(185)  评论(0编辑  收藏  举报