一个无序实数数组中的相邻两个元素的最大差值

一个无序的实数数组a[i],要求求里面大小相邻的实数的差的最大值。比如 double a[]={1,5,4,0.2,100} 这个无序的数组,相邻的数的最大差值为100-5=95.

题目分析:这题有个简单的做法,首先就是对数组进行一个排序,然后扫面一遍数据就可以得到结果;但时间复杂度依赖于排序时间复杂度,一般为O(nlog n)。

然而一般面试官会让给出一个线性空间和线性时间复杂度的算法。这时就用到了桶排序的思想。

解题思路

解题过程如下:

  1. 扫面一遍数组,找到数组中的最大max,最小min值。
  2. 将[min, max]区间分为n-1个区间段(每个区间段对应一个桶bucket),每个桶用一对有序实数对[a,b] 来表示桶内的数。
  3. 再次从头到尾扫描数组,将每个元素添加到相应的桶bucket里面。 注意:有的桶为空(不含任何数据)
  4. 然后按顺序访问每个( 非空 )的相邻的桶进行比较。若两个非空的相邻的桶分别为(a,b) , (c,d),那么这两个 非空 相邻的桶的距离为 c-b。最后选择最大的非空相邻同的距离返回即可。
注意:
  • 上述算法是空间和时间复杂度均是O(n)
  • 我们不需要计算桶内元素的距离(如b-a),因为数组最大间隔max-min分成n-1个桶,n个元素中一定有两个相邻元素的距离大于桶内的距离(想一想抽屉原理或者鸽巢原理),所以桶内的距离是不用算的
源代码:C++
在算法的实现上,注意桶为空的标记。
此外为了方便,算法实现过程中,桶内保存的不是相应的元素,而是 相应元素在数组中对应的index
   
   
#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;
}

备注:
这道题网上有人给出了相应的解法,但对桶为空的标记没有处理好,不能好好的work。如:http://blog.csdn.net/joanlynnlove/article/details/7706194


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值