(排序数组)
题目:输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。、
分析:如果我们不考虑时间复杂度,最简单想法是计算任一一个数字与其他n-1个数字的和,判断是否等于给定值。复杂度是O(n2)。
由于该序列是升序数组,我们假设随意取数组中的两个数,如果和等于给定值,那么就是我们所找的两个数;如果小于给定值,很容易想到,更小的那个数应该更大,即下标应该更大,那么对应的数会更大;如果大于给定值,那么更大的那个应该更小,即下标应该更小。因此我们首先找到第一个和最后一个数字,再逐渐让所取的数字往中间靠拢。
问题是这样的思路是不是正确的呢?这需要严格的数学证明。感兴趣的读者可以自行证明一下。
#include<iostream> using namespace std; int num[6] = {1,2,4,7,11,15}; int main() { int n = 6; int sum; scanf("%d", &sum); int i = 0; int j = n - 1; int tmp; bool solve = false; while(i < j){ tmp = num[i] + num[j]; if(tmp == sum){ solve = true; cout << num[i] << ' ' << num[j] << endl; break; } else if(tmp < sum){ i ++; } else{ j --; } } if(!solve){ cout << "there is not." << endl; } system("pause"); }
(无序数组)
但是有个前提条件,即num数组中的值都在low~high给的范围内。
生成一个bool型的数组,取num数组中的每个值,令bool型数组相应的下标的值为true,否则为false。
则此时的bool数组则相当于上面有序数组了,则用相同的方法找到和为给定值的两个数字。
void getsum(int num[], int n, int sum) { bool arr[high - low + 1]; memset(arr, false, sizeof(arr)); for(int i = 0; i < n; i ++){ arr[num[i] - low] = true; } int i = 0; int j = high - low; int tmp; bool solve = false; while(i < j){ while(i < j && !arr[i]){ i ++; } while(i < j && !arr[j]){ j --; } tmp = i + j; if(tmp == sum){ solve = true; cout << i << ' ' << j << endl; i ++; j --; } else if(tmp < sum){ i ++; } else{ j --; } } if(!solve){ cout << "There are not two numbers" << endl; } }