题目:输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。要
求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。
分析:如果我们不考虑时间复杂度,最简单想法的莫过去先在数组中固定一个数字,再依次判断数组中剩下的n-1个数字
与它的和是不是等于输入的数字。可惜这种思路需要的时间复杂度是O(n2)。
我们假设现在随便在数组中找到两个数。如果它们的和等于输入的数字,那太好了,我们找到了要找的两个数字;如果
小于输入的数字呢?我们希望两个数字的和再大一点。由于数组已经排好序了,我们是不是可以把较小的数字的往后面
移动一个数字?因为排在后面的数字要大一些,那么两个数字的和也要大一些,就有可能等于输入的数字了;同样,当
两个数字的和大于输入的数字的时候,我们把较大的数字往前移动,因为排在数组前面的数字要小一些,它们的和就有
可能等于输入的数字了。
我们把前面的思路整理一下:最初我们找到数组的第一个数字和最后一个数字。当两个数字的和大于输入的数字时,把
较大的数字往前移动;当两个数字的和小于数字时,把较小的数字往后移动;当相等时,打完收工。这样扫描的顺序是
从数组的两端向数组的中间扫描。
问题是这样的思路是不是正确的呢?这需要严格的数学证明。感兴趣的读者可以自行证明一下。
//============================================================================
// Name : FindToNumberEqualSum.cpp
// Author : Lee
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
using namespace std;
class LeeCom{
public:
bool findTwoNum(int & first,int & second,int sum,int datas[],int len);
};
bool LeeCom::findTwoNum(int & first,int & second,int sum,int datas[],int len){
first=0;
second=len-1;
while(first<second){
if(datas[first]+datas[second]==sum){
return true;
}
else if(datas[first]+datas[second]>sum){
second--;
}else{
first++;
}
}
return false;
}
int main() {
cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
int a[7]={1,2,3,5,6,7,8};
LeeCom lee;
int first=0;
int second=0;
if(lee.findTwoNum(first,second,7,a,7)){
cout<<a[first]<<"and"<<a[second]<<endl;
}
return 0;
}