/************************************************************************* > 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循环的时间复杂度;