• 【算法10】在升序数组中查找和等于给定值的两个数


    【题  目】输入一个已经按升序排列的数组,一个给定的数字,在数组中查找两个数,使得它们的和等于给定的数字。要求时间复杂度为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/。对解题思路有任何建议,欢迎在评论中告知。

  • 相关阅读:
    react-动画
    react-json渲染
    SQL 只取重复记录一条记录并且是最小值
    SQL 函数:树结构指定父节点遍历所有的子节点
    EasyUI treegrid 删除一条或多条记录
    String.Format数字格式化输出 {0:N2} {0:D2} {0:C2} (转)
    EasyUI 左,右(上、下)布局
    DataTable 树形构造加全部
    easyui datagrid 格式化列显示两位小数、千分位
    c# 判断文件是否已使用
  • 原文地址:https://www.cnblogs.com/python27/p/2274991.html
Copyright © 2020-2023  润新知