《编程之美》——寻找最近点对

问题:
给定平面上两个点的坐标,找出距离最近的两个点。

分析与解法:
一般思路是蛮力算法,两两求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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
设计模式是一种经过总结、优化的、可重复使用的设计经验的总结。它是软件工程中一种解决特定问题的可复用方案。设计模式不是一成不变的,而是可以根据不同的需求进行变化,以达到最佳的效果。设计模式可以提高程序的可读性、可维护性、可扩展性,同时也可以提高程序的性能和稳定性。 设计模式可以分为三种类型:创建型模式、结构型模式和行为型模式。创建型模式用于描述对象的创建过程,结构型模式用于描述对象之间的关系,行为型模式用于描述对象的行为和交互。本篇文章将介绍一些常用的设计模式。 1. 工厂模式(Factory Pattern) 工厂模式是一种常用的创建型模式,它使用一个工厂方法来创建对象,而不是通过直接调用构造函数。工厂模式可以隐藏对象的创建过程,使代码更加灵活和易于维护。工厂模式可以分为简单工厂模式、工厂方法模式和抽象工厂模式。 2. 单例模式(Singleton Pattern) 单例模式是一种创建型模式,它保证一个类只有一个实例,并提供一个全局访问。单例模式可以保证对象的唯一性,避免了多个实例对系统资源的浪费。 3. 代理模式(Proxy Pattern) 代理模式是一种结构型模式,它为一个对象提供一个代理,以控制对这个对象的访问。代理模式可以增加对象的安全性,降低对象的访问成本,同时也可以提高程序的灵活性和可扩展性。 4. 装饰器模式(Decorator Pattern) 装饰器模式是一种结构型模式,它动态地给一个对象添加一些额外的职责,而不需要修改这个对象的代码。装饰器模式可以避免使用子类来扩展对象的功能,从而使代码更加灵活和可扩展。 5. 观察者模式(Observer Pattern) 观察者模式是一种行为型模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生改变时,会通知所有的观察者对象,使它们能够及时更新自己的状态。 以上是五种常用的设计模式,它们在软件开发中都有着广泛的应用。设计模式可以帮助我们更好地组织代码、降低程序的耦合度、提高程序的可扩展性和可维护性,是一种非常重要的编程技巧。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值