【题 目】输入一个已经按升序排列的数组,一个给定的数字,在数组中查找两个数,使得它们的和等于给定的数字。要求时间复杂度为O(n),如果存在多对满足条件的数字对,只给出一对即可。例如:输入数组『1,2,4,7,11,15』,给定一个数字15,那么输出应该为『4,11』.
【思路1】我们先不考虑时间复杂度为O(n),按照最直观的思路来考虑,容易想到,我们一次固定数组中的一个数字,然后遍历这个数字之后的各个数字,判断和是否为给定的和,这样的时间复杂度为O(n2)。容易写出如下的代码:
1 #include<iostream>
2 #include<string>
3 using namespace std;
4
5 bool FindTwoNumbers(int array[],int length,int sum,int &num1,int &num2)
6 {
7 if(array == NULL || length < 2)
8 return false;
9
10 for(int i = 0;i < length - 1;++i)
11 {
12 for(int j = i + 1;j < length;++j)
13 {
14 if(array[i] + array[j] == sum)
15 {
16 num1 = array[i];
17 num2 = array[j];
18 return true;
19 }
20 }
21 }
22
23 return false;
24 }
25
26 int main()
27 {
28 cout<<"Enter the length of your array:"<<endl;
29 int arraylength = 0;
30 cin>>arraylength;
31 int *p = new int[arraylength];
32
33 cout<<"Enter the numbers in your array:"<<endl;
34 for(int i = 0;i < arraylength;++i)
35 {
36 cin>>p[i];
37 }
38
39 cout<<"Enter a sum you want to find:"<<endl;
40 int result = 0;
41 cin>>result;
42
43 int a = 0;
44 int b = 0;
45 FindTwoNumbers(p,arraylength,result,a,b);
46
47 cout<<"the two numbers are:"
48 <<"\t"<<a<<"\t"<<b<<endl;
49
50 delete[] p;
51 return 0;
52 }
运行结果如下:
【思路2】上面的算法时间复杂度为O(n2),但是这个算法有一个好处就是,对于不排序的数组也是能够适用的,因为我们采用的方法是遍历,对于排序不排序,我们并不关心。这也从一个侧面说明了上面的算法时间复杂度较高的原因是:我们并没有充分利用数组是按升序排列的这个条件。如果考虑这个条件,我们会怎么做?
我们考虑一种特殊的情况,数组是严格的等差数列,那么给定一个和,如果能够找到一对整数满足题条件,那么根据等差数列的性质,较大的数想左移动一个数字,叫小的数向有移动一个数字,就又找到了另一对满足条件的数对。那么对于一般情况,我们能否这样考虑:首先判断第一个数字和最后一个数字的和,如果这个和大于给定的和,那么就让最后一个数字左移;反之,如果它们的和小于给定的和,就让第一个数字右移,这样是合乎逻辑的,然而这个算法容易使人产生一个疑问,会不会漏掉呢?这需要严格的数学证明,笔者暂时还不能给出证明,待日后补充,也希望数学很牛的同学不吝赐教。该思路代码如下:
1 #include<iostream>
2 #include<string>
3 using namespace std;
4 bool FindTwoNumbers(int array[],int length,int sum,int &num1,int &num2)
5 {
6 //无效输入,返回false
7 if(array == NULL || length < 2)
8 return false;
9
10 int *start = &array[0];
11 int *end = &array[length -1];
12
13 while(start < end)
14 {
15 if((*start + *end) == sum)
16 {
17 num1 = *start;
18 num2 = *end;
19 return true;
20 }
21
22 //小于给定和,较小的数右移
23 else if((*start + *end) < sum)
24 {
25 start++;
26 }
27
28 //大于给定和,较大的数左移
29 else if((*start + *end) > sum)
30 {
31 end--;
32 }
33 }
34
35 return false;
36 }
37
38
39 int main()
40 {
41 cout<<"Enter the length of your array:"<<endl;
42 int arraylength = 0;
43 cin>>arraylength;
44 int *p = new int[arraylength];
45
46 cout<<"Enter the numbers in your array:"<<endl;
47 for(int i = 0;i < arraylength;++i)
48 {
49 cin>>p[i];
50 }
51
52 cout<<"Enter a sum you want to find:"<<endl;
53 int result = 0;
54 cin>>result;
55
56 int a = 0;
57 int b = 0;
58 FindTwoNumbers(p,arraylength,result,a,b);
59
60 cout<<"the two numbers are:"
61 <<"\t"<<a<<"\t"<<b<<endl;
62
63 delete[] p;
64 return 0;
65 }
运行结果如下:
References:
程序员面试题精选100题:http://zhedahht.blog.163.com/blog/static/2541117420072143251809/
注:
1)本博客所有的代码环境编译均为win7+VC6。所有代码均经过博主上机调试。
2)博主python27对本博客文章享有版权,网络转载请注明出处http://www.cnblogs.com/python27/。对解题思路有任何建议,欢迎在评论中告知。