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

来源:互联网 发布:最新版农村淘宝下载 编辑:程序博客网 时间:2024/05/18 02:01

寻找和为定值的两个数

from https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/02.02.md

题目描述

输入一个数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。

要求时间复杂度是O(N)。如果有多对数字的和等于输入的数字,输出任意一对即可。

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

解法一

根据前面的分析,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)的空间存储第二个数组。

解法二

当题目对时间复杂度要求比较严格时,我们可以考虑下用空间换时间,上述解法一即是此思想,此外,构造hash表也是典型的用空间换时间的处理办法。

即给定一个数字,根据hash映射查找另一个数字是否也在数组中,只需用O(1)的时间,前提是经过O(N)时间的预处理,和用O(N)的空间构造hash表。

但能否做到在时间复杂度为O(N)的情况下,空间复杂度能进一步降低达到O(1)呢?

解法三

如果数组是无序的,先排序(N log N),然后用两个指针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 log N + N)=O(N log N)。

如果原数组是有序的,则不需要事先的排序,直接用两指针分别从头和尾向中间扫描,O(N)搞定,且空间复杂度还是O(1)。

void TwoSum(int data[], unsigned int length, int sum){    //sort(s, s+n);   如果数组非有序的,那就事先排好序O(N log N)    int begin = 0;    int end = length - 1;    //俩头夹逼,或称两个指针两端扫描法,很经典的方法,O(N)    while (begin < end)    {        long currSum = data[begin] + data[end];        if (currSum == sum)        {            //题目只要求输出满足条件的任意一对即可            printf("%d %d\n", data[begin], data[end]);            //如果需要所有满足条件的数组对,则需要加上下面两条语句:            //begin++            //end--            break;        }        else{            if (currSum < sum)                begin++;            else                end--;        }    }}


0 0
原创粉丝点击