问题:
给定平面上两个点的坐标,找出距离最近的两个点。
分析与解法:
一般思路是蛮力算法,两两求N个点之间的距离并比较,得出最大距离,时间复杂度为O(N^2)。
优化算法是采用分治的思想,将N个点先按照 x 轴的坐标的中值 x = mX 平均分为左右两组,分别求出 xL 和 xR 中的最近点对的距离,因为最近点对一定是出现 xL 或 xR 中,或者是xL中的一个点与 xR 中的一个点之间,所有再将左右最近点对间的距离进行比较,取较小值 mDist,在带状区域 x=mX-mDist 和x=mX+mDist 之间以 y 轴坐标进行归并排序,如果一个点对的距离小于mDist,那么它们一定在一个mDist*(mDist+mDist) 的区域中
根据理论,可以用O(N)的时间复杂度完成带状区域中最近点对的查找,总的时间复杂度是O(NlogN)。
扩展问题:
1.找出一维数组中相邻两个数的最大差值。
2.找出平面上距离最远的两个点之间的距离。
分析与解法:
1.一般思路是使用排序算法将数组转化为有序数组时间复杂度为O(NlogN),在通过一次遍历数组得到相邻两个数的最大差值,时间复杂度为O(N),总的时间复杂度为O(nlogn)。
为了提高时间复杂度可以使用空间换时间的方法,使用桶排序求解,其时间复杂度和空间复杂度都为O(n)。
(1) 扫面一遍数组,找到数组中的最大值max,最小值min。时间复杂度O(2*n)。
(2) 将[min, max]区间分为n-1个区间段(每个区间段对应一个桶bucket)。
(3) 再次从头到尾扫描数组,将每个元素添加到相应的桶bucket里面。 注意:有的桶为空(不含任何数据),可以使用两个变量记录下桶中的最小值first和最大值second。时间复杂度O(2*n)。
(4) 然后按顺序将每个( 非空 )的相邻的桶进行比较。桶内元素之间的差值肯定不是最大差值,故不需要计算,最大差值只可能是前一个桶的最大值与后一个桶中的最小值之间的差值。最后选择最大的非空相邻桶的距离返回即可。时间复杂度O(n)。
代码:
#include <iostream>
#include <vector>
#include <utility>
using namespace std;
/**一个无序的实数数组,求它们最近邻的两个值的最大差值**/
double maxDiff(double a[], int n)
{
double max = a[0];
double min = a[0];
for (int i=1; i<n; ++i)
{
if (max < a[i])
{
max = a[i];
}
if (min > a[i])
{
min = a[i];
}
}
double bar = (max - min)/(n-1);
int pos; //pair<first,second> : first表示桶中最小元素的index,second表示桶中最大元素的index
vector< pair<int,int> > buckets(n,make_pair(-1,-1));
//这里桶内存相应数据的下标,而不是相应的数据,方便后面的数据计算,以免有精度损失。
for (int i=0; i<n; i++)
{
pos = (int)((a[i] - min)/bar);
if ((buckets[pos].first == -1) && (buckets[pos].second == -1))
{
//下标比较,若为double型比较注意精度问题
buckets[pos].first = buckets[pos].second = i;
}
else
{
if (a[buckets[pos].first] > a[i])
buckets[pos].first = i;
if (a[buckets[pos].second] < a[i])
buckets[pos].second = i;
}
}
int lastIx=0;
double max_diff = 0;
double tmp_diff = 0;
for (int i=1; i<n; ++i)
{
//计算桶之间的距离
if ((buckets[i].first == -1) && (buckets[i].second == -1))
{
//桶为空的标志,不处理
}
else
{
tmp_diff = a[buckets[i].first] -a[buckets[lastIx].second];
if (tmp_diff > max_diff)
{
max_diff = tmp_diff;
}
lastIx = i;
//lastIx指上一个非空桶的index,且第一个桶和最后一个桶肯定非空。
}
}
return max_diff;
}
int main()
{
double a[]={2,4,8,16,19.0,7,7,30};
cout<<maxDiff(a,8)<<endl;
return 0;
}
2.对于平面上有n个点,这一对最远点必然存在于这n个点所构成的一个凸包上。然后使用凸包算法求解。
代码:
http://blog.csdn.net/zmlcool/article/details/6727351
文章及代码参考以下博文:
http://blog.csdn.net/acema/article/details/38682943utm_source=tuicool&utm_medium=referral