算法导论P23题目2.37

请给出一个运行时间为O(n lgn)的算法,使之在给定一个由n个整数构成的集合S和另一个整数x时,判断出S中是否存在有两个其和等于x的元素。

以下思路一 和 思路二来自 http://blog.csdn.net/magic_coder/article/details/6435098

思路一 :我们最容易想到的是O(n2)的算法,大致伪码即:

1 findX(A, x){

2     for i=0 to length[A] {

3         key = A[i]

4             for j=0 to length[A]{

5                  if(j != i && key + A[j] == x ){return true}

6     }

7     return false

8 }

这里的算法不符合O(n lgn),所以不行。

思路二:改进思路一中的算法,使第一层循环里面的4--5行的效率为 lgn。

既然4-5行的目的是找到某个符合条件的值,那么我想到了二分查找,二分查找是一个最坏O(lgn)的查找算法,但是前提是集合S有序,于是先要进行排序。伪码如下:

1 findX(A, x){

2     mergeSort(A, 0, length[A]);

3     for i=0 to length[A] {

4         key = A[i]

6         if( binarySearch(A, x-key, 0, length[A]) != i ){return true}

7     }

8     return false

9 }

第2行的归并排序运行时间为O(n lgn), 第3-7行的运行时间为O(n)*O(lgn)= O(nlgn),故总运行时间为O(nlgn)。

思路三来自http://blog.csdn.net/intrepyd/article/details/4340638

思路三:

1.        对数组S进行归并排序。

2.        构造数组S’={z : z=x-y, y∈S},并排序。由于S已经有序,构造与排序可一并完成。

3.        删除S中重复的元素使仅保留一个,对S’进行同样的操作。

4.        合并S和S’,并保证合并后有序,这里可以使用归并排序的思想。

5.        如果在合并后的数组中存在连续两个相同的元素,并且这种元素的个数大于1,那么有解。

设想在合并后的数组中存在连续两个w,则w分别属于S和S’,那么S中存在y使得w=x-y,即x=y+w。因此,S中元素w和y的和为x。

步骤1的运行时间为Θ(n lg n),其余步骤运行时间为Θ(n),因此总的时间代价为Θ(n lg n)。

思路四:前提是所有元素非负

1 首先通过合并排序对数组元素排序,时间 O(nlgn)

2 用二分查找方法找到一个数组下标 pEnd,使给定的 key≤array[i], 时间 O(lgn)

   注意: P23页的 2.3-6题的插入排序就可以用这种方法实现

3 在下标0 - pEnd之间搜索满足条件的数据,这里用到思路二的思想。时间 O((pEnd)lg(pEnd))

代码如下:

/*
* findSumofdata.cpp
* 算法导论 P.23 2.3-7
* Created on: 2011-12-27
* Author: LiChanghai
*/

#include "myheder.h"

//该函数寻找下标 pEnd
bool binaryFind(const int array[ ], int n, int &pEnd, int key)
{
/* 找到下标 pEnd,使 key 小于等于 array[pEnd] */
int low = 0, high = n-1;
int middle;
//元素个数大于1时进行二分查找
while(low < high)
{
middle = (low+high)/2;
if(key <= array[middle])
high = middle;
else
low = middle+1;
}
//只剩一个元素时,确定 pEnd 的值
if(key >= array[low])
{
pEnd =low;
return 1;
}
else
if(low != 0)
{
pEnd = low -1;
return 1;
}
else
return 0; //所有的数据都比 key 大,返回0表示没找到
}

bool findSumofdata(int array[ ], int n, int key)
{
//首先调用合并排序函数对数组进行排序,时间为 O(nlgn)
//mergeSort(array);

// 定义 pEnd, 计算pEnd 使 key≤array[pEnd], 时间为 O(lgn)
int pEnd;
//如果所有数据都比key大,显然要找的数据不存在
if( ! binaryFind(array, n, pEnd, key) )
return 0;

//现在在 0--pEnd 之间寻找满足条件的数据,时间小于O((pEnd)lg(pEnd))≤O(nlgn)
// 首先对于特定的 array[i], 需要寻找一个数a, 使 a+array[i]=key
// 即需要寻找 a=key-array[i]
for(int i=0; i != pEnd; ++i) //该语句的时间为 O(pEnd)≤O(n)
{
int index=binarySearch(array, i+1, pEnd, key-array[i]); //该句的时间小于 O(lg(pEnd))
if(index != -1)
return 1;
}
//如果没找到,返回0
return 0;
}



原文地址:https://www.cnblogs.com/haigege/p/2303968.html