寻找两个数的和为定值的算法

转载 2015年07月06日 23:00:41
题目:输入一个数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。
要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。

例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。

  1. 直接穷举,从数组中任意选取两个数,判定它们的和是否为输入的那个数字。此举复杂度为O(N^2)。很显然,我们要寻找效率更高的解法。
  2. 题目相当于,对每个a[i],查找sum-a[i]是否也在原始序列中,每一次要查找的时间都要花费为O(N),这样下来,最终找到两个数还是需要O(N^2)的复杂度。那如何提高查找判断的速度呢?答案是二分查找,可以将O(N)的查找时间提高到O(logN),这样对于N个a[i],都要花logN的时间去查找相对应的sum-a[i]是否在原始序列中,总的时间复杂度已降为O(N*logN),且空间复杂度为O(1)。(如果有序,直接二分O(N*logN),如果无序,先排序后二分,复杂度同样为O(N*logN+N*logN)=O(N*logN),空间总为O(1))。
  3. 有没有更好的办法呢?咱们可以依据上述思路2的思想,a[i]在序列中,如果a[i]+a[k]=sum的话,那么sum-a[i](a[k])也必然在序列中,举个例子,如下:
    原始序列:1、 2、 4、 7、11、15     用输入数字15减一下各个数,得到对应的序列为:
    对应序列:14、13、11、8、4、 0      
    第一个数组以一指针i 从数组最左端开始向右扫描,第二个数组以一指针j 从数组最右端开始向左扫描,如果下面出现了和上面一样的数,即a[*i]=a[*j],就找出这俩个数来了。如上,i,j最终在第一个,和第二个序列中找到了相同的数4和11,,所以符合条件的两个数,即为4+11=15。怎么样,两端同时查找,时间复杂度瞬间缩短到了O(N),但却同时需要O(N)的空间存储第二个数组(@飞羽:要达到O(N)的复杂度,第一个数组以一指针i 从数组最左端开始向右扫描,第二个数组以一指针j 从数组最右端开始向左扫描,首先初始i指向元素1,j指向元素0,谁指的元素小,谁先移动,由于1(i)>0(j),所以i不动,j向左移动。然后j移动到元素4发现大于元素1,故而停止移动j,开始移动i,直到i指向4,这时,i指向的元素与j指向的元素相等,故而判断4是满足条件的第一个数;然后同时移动i,j再进行判断,直到它们到达边界)。
  4. 当然,你还可以构造hash表,正如编程之美上的所述,给定一个数字,根据hash映射查找另一个数字是否也在数组中,只需用O(1)的时间,这样的话,总体的算法通上述思路3 一样,也能降到O(N),但有个缺陷,就是构造hash额外增加了O(N)的空间,此点同上述思路 3。不过,空间换时间,仍不失为在时间要求较严格的情况下的一种好办法。
  5. 如果数组是无序的,先排序(n*logn),然后用两个指针i,j,各自指向数组的首尾两端,令i=0,j=n-1,然后i++,j--,逐次判断a[i]+a[j]?=sum,如果某一刻a[i]+a[j]>sum,则要想办法让sum的值减小,所以此刻i不动,j--,如果某一刻a[i]+a[j]<sum,则要想办法让sum的值增大,所以此刻i++,j不动。所以,数组无序的时候,时间复杂度最终为O(n*logn+n)=O(n*logn),若原数组是有序的,则不需要事先的排序,直接O(n)搞定,且空间复杂度还是O(1),此思路是相对于上述所有思路的一种改进。(如果有序,直接两个指针两端扫描,时间O(N),如果无序,先排序后两端扫描,时间O(N*logN+N)=O(N*logN),空间始终都为O(1))。(与上述思路2相比,排序后的时间开销由之前的二分的n*logn降到了扫描的O(N))。

总结

  • 不论原序列是有序还是无序,解决这类题有以下三种办法:1、二分(若无序,先排序后二分),时间复杂度总为O(n*logn),空间复杂度为O(1);2、扫描一遍X-S[i]  映射到一个数组或构造hash表,时间复杂度为O(n),空间复杂度为O(n);3、两个指针两端扫描(若无序,先排序后扫描),时间复杂度最后为:有序O(n),无序O(n*logn+n)=O(n*logn),空间复杂度都为O(1)。
  • 所以,要想达到时间O(N),空间O(1)的目标,除非原数组是有序的(指针扫描法),不然,当数组无序的话,就只能先排序,后指针扫描法或二分(时间n*logn,空间O(1)),或映射或hash(时间O(n),空间O(n))。时间或空间,必须牺牲一个,自个权衡吧。
  • 综上,若是数组有序的情况下,优先考虑两个指针两端扫描法,以达到最佳的时(O(N)),空(O(1))效应。否则,如果要排序的话,时间复杂度最快当然是只能达到N*logN,空间O(1)则是不在话下。                                        

参考代码如下:
Pair findSum(int *s,int n,int x)     
{     
    //sort(s,s+n);   如果数组非有序的,那就事先排好序O(N*logN)     
      
    int *begin=s;     
    int *end=s+n-1;     
      
    while(begin<end)    //俩头夹逼,或称两个指针两端扫描法,很经典的方法,O(N)    
    {     
        if(*begin+*end>x)     
        {     
            --end;     
        }     
        else if(*begin+*end<x)     
        {     
            ++begin;     
        }     
        else    
        {     
            return Pair(*begin,*end);     
        }     
    }     
      
    return Pair(-1,-1);     
}     
  
//或者如下编写,  
//代码二  
//copyright@ zhedahht && yansha  
//July、updated,2011.05.14。  
bool find_num(int data[], unsigned int length, int sum, int& first_num, int& second_num)  
{     
    if(length < 1)  
        return true;  
      
    int begin = 0;  
    int end = length - 1;  
      
    while(end > begin)  
    {  
        long current_sum = data[begin] + data[end];  
          
        if(current_sum == sum)  
        {  
            first_num = data[begin];  
            second_num = data[end];  
            return true;  
        }  
        else if(current_sum > sum)  
            end--;  
        else  
            begin++;  
    }  
    return false;  
}  


算法理解——寻找和为定值的两个数/多个数

1 寻找和为定值的两个数 题目:输入一个数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。 example:  例如输入数组1、2、4、7、11、15和数字15。由于4+11=...
  • jinyongqing
  • jinyongqing
  • 2013年09月26日 15:52
  • 4239

【算法题】找到数组中和为固定值的两个元素

题目:编写一个函数,输入为一个int型的数组numbers和一个int型变量target,找到这个数组中和为target的两个元素,输出其index。 假设每组输入有且仅有一组输出 示例: Input...
  • u010515761
  • u010515761
  • 2015年02月03日 16:08
  • 1408

面试算法题:数组中两个数之和为定值,找出这对数的下标

题目 已知一个数是一个数组中两个数据之和,找出这个数组中某一对符合条件的数 例如:a[]={1,2,3,5,8} n=10,则输出{2,8} 思路 最笨的办法就是从第一个数开始,依次和后...
  • UESTCAA
  • UESTCAA
  • 2016年11月16日 14:46
  • 1308

数据结构学习笔记6-寻找和为定值的两个数(二分查找)

本文参考了文章《寻找和为定值的两个数》寻找和为定值的两个数题目描述输入一个数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。要求时间复杂度是O(N)。如果有多对数字的和等于输入的数...
  • xiaoluodecai
  • xiaoluodecai
  • 2015年08月20日 11:20
  • 329

快速寻找满足条件的两个数(两数之和为给定值)

首先递增排序,首尾指针相加,大于目标数,尾指针前移,小于目标数,首指针后移,继续比较,直到两指针相遇。 程序如下,借用这个问题,练习一下MergeSort #include #include...
  • bertzhang
  • bertzhang
  • 2012年02月08日 10:32
  • 902

读取一串整数,寻找合适的数据结构和算法,实现插入元素track(int x) 方法,以及GetRankOfNumber(int x)方法,返回值为小于等于x的元素个数(不包括x本身)

题目:《程序员面试金典(第5版)》
  • bupt8846
  • bupt8846
  • 2014年11月19日 11:53
  • 387

寻找和为定值的任意个数(01背包)

这个问题是在July的《编程之法》上看到的,题目要求是:输入两个数字n与sum,在1~n中寻找哪些数字之和等于sum。 很明显这是个典型的01背包问题,因为每一个元素只有要与不要两种选择~ #in...
  • qq973177663
  • qq973177663
  • 2016年01月15日 20:27
  • 320

Lettcode | Two Sum(两个数的和等于定值)

题目: Given an array of integers, find two numbers such that they add up to a specific target...
  • a45872055555
  • a45872055555
  • 2014年07月03日 17:44
  • 818

【剑指offer学习】求和为定值的两个数(拓展)

【剑指offer学习】求和为定值的两个数(拓展)
  • u013476464
  • u013476464
  • 2014年11月03日 19:12
  • 883

寻找最大K个数topK算法

寻找一个数组中,最大的K个数,例如,我们的数组 int treeNodeValue[]={5,3,7,2,4,6,8,9,0,1}; 寻找最大的三个数,k=3;这三...
  • jpsiyu
  • jpsiyu
  • 2013年10月27日 09:07
  • 521
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:寻找两个数的和为定值的算法
举报原因:
原因补充:

(最多只允许输入30个字)