高速寻找满足条件的两个数

时间:2014.07.17

地点:基地

-------------------------------------------------------------------------------------

一、问题描写叙述

  给定一个数组。要求高速查找出当中的两个值。他们的和为一个给定的值。

比方给定数组:1 4 5 6 8  9,和给定值9。我们能找出4+5=9为所要的数值

-------------------------------------------------------------------------------------

二、各种解法

2.1穷举法

  对给定集合从中取出随意值求和,看是否等于给定和值,显然由组合公式知:其复杂度为N(N-1)/2,即O(N^2)。我们要求尽可能减少算法时间复杂度和算法空间复杂度,这个算法比較原始。

2.2先排序后查找

  假定给定数字和为sum,对数组中的每一个数字arr[i],理想上是要有另外一个数字sum-arr[i]存在数组中即为查找成功。于是问题转换成了一个查找问题。而我们知道查找算法中最快的莫过于二分查找。时间复杂度为O(logN),但二分查找的前提是有序序列,于是我们要先对数组进行排序。我们也知道快排、堆排、归排等都是时间复杂度为O(NlogN)的排序算法。于是针对数组中的每一个数arr[i],都须要花费O(logN)的时间去查找相应的sum-arr[i]是否存在,于是总的时间复杂度为O(NlogN),在这里我们排序也需耗时O(NlogN)。但好在排序仅仅需一次。于是时间复杂度依然还是O(NlogN)。

使用二分查找时要注意:

1.将数组划分为两个子部分时,中间分界为:

middle=first+size/2

2.左边子部分可能略多,从first開始,大小为size/2

3.右边子部分可能略少,从middle+1開始,大小为(size-1)/2

2.3使用哈希查找

  在2.2节,我们已经将问题转换成了查找问题。其实,对于查找问题,若不惜代价追求速度的话,哈希查找最快,每次查找时间复杂度为O(1),于是在这里我们仅仅需O(N)就可以完毕任务。

此种方法须要添加额外的存储空间。

2.4双端扫描

  首先若数组无序。排序还是要排,时间复杂度为O(NlogN)。但若数组有序,则可直接O(N)完毕任务,在这里我们如果数组是有序的,如今才用双指针双端扫描法对整个数组扫描的策略:
首先,设定两个指针begin 和 end。分别指向数组首和尾,

然后,逐次推断arr[*begin]+arr[*end]和给定的sum进行大小比較

i.若大于,说明两数和过大。运行--end,缩减两数和

ii.若小于。说明两数和过小,运行++begin。放大两数和

iii.若等于,正是我们所要。返回这个数值对

双端扫描的代码例如以下:

pair FindSumPair(int* arr, int n, int sum)
{
	//Sort(arr,arr+n);               //若数组无序,则先对数组进行排序
	int* begin = arr;
	int* end = arr + n - 1;
	int tem_sum = 0;
	while (begin < end)
	{
		tem_sum = (*begin) + (*end);
		if (tem_sum>sum)
			--end;
		else if (tem_sum < sum)
			++begin;
		else
			return pair(*begin, *end);
	}
	return pair(-1, -1);
}

-------------------------------------------------------------------------------------

三、扩展

2010年中兴面试题-编程求解:
输入两个整数 n 和 m。从数列1,2,3.......n 中 随意取几个数,
使其和等于 m, 要求将当中全部的可能组合列出来。


引用算法之道JULY博客中的代码例如以下:

#include<list>  
#include<iostream>  
using namespace std;  
  
list<int>list1;  
void find_factor(int sum, int n)   
{  
    // 递归出口  
    if(n <= 0 || sum <= 0)  
        return;  
      
    // 输出找到的结果  
    if(sum == n)  
    {  
        // 反转list  
        list1.reverse();  
        for(list<int>::iterator iter = list1.begin(); iter != list1.end(); iter++)  
            cout << *iter << " + ";  
        cout << n << endl;  
        list1.reverse();      
    }  
      
    list1.push_front(n);      //典型的01背包问题  
    find_factor(sum-n, n-1);   //放n。n-1个数填满sum-n  
    list1.pop_front();  
    find_factor(sum, n-1);     //不放n。n-1个数填满sum   
}  
  
int main()  
{  
    int sum, n;  
    cout << "请输入你要等于多少的数值sum:" << endl;  
    cin >> sum;  
    cout << "请输入你要从1.....n数列中取值的n:" << endl;  
    cin >> n;  
    cout << "全部可能的序列。例如以下:" << endl;  
    find_factor(sum,n);  
    return 0;  
}  



posted @ 2019-05-31 17:36  ldxsuanfa  阅读(92)  评论(0编辑  收藏  举报