相邻两数最大差值

来源:互联网 发布:冒险岛市场实时数据 编辑:程序博客网 时间:2024/04/29 06:19


有一个整形数组A,请设计一个复杂度为O(n)的算法,算出排序后相邻两数的最大差值。

给定一个int数组AA的大小n,请返回最大的差值。保证数组元素多于1个。

测试样例:
[1,2,5,4,6],5
返回:2


解析:使用bucket排序思想,把大小为n的数组分成(max-min)/n个区间,显然这个区间是1 ~ n。

映射函数如下:

((num - min) * n / (max - min));

这样写是因为(num-min) / ((max-min) / n) =  ((num - min) * n / (max - min));

比如num=6,min=1,max=6,(6-1) * 5 / (6-1) = 5,所以6在5号桶。这个映射函数决定了桶序号不可能为0,所以编程时要先剔除为0的空桶。

由于在任何一个桶中任何两个数的差值都不可能大于区间差值,而在空桶左右两边不空的桶里,相邻数的差值肯定大于区间值。所以产生最大差值的两个相邻数肯定来自不同的桶。所以只要计算桶之间数的间距就可以,也就是只用记录每个桶的最大值和最小值,最大差值可能来自某个非空桶的最小值减去前一个非空桶的最大值。


代码如下:

class Gap {public:    int maxGap(vector<int> A, int n) {       if(n < 0 || ((A.size()==0) ^ (n==0)))            return -1;                       int res = 0;       if(n < 2)        return res;                       int max = A[0], min = A[0];        for(int i=1; i<n; ++i){            if(A[i] > max)                max = A[i];           if(A[i] < min)                min = A[i];        }        if(max == min)        return res;                vector<bool> has_num(n+1, false);   //用来标记是否是非空桶        vector<int> maxs(n+1, 0);        vector<int> mins(n+1, 0);        for(int i=0; i<n; ++i){            int bucket_id = get_bucket_id(A[i], n, min, max);            maxs[bucket_id] = has_num[bucket_id] ? std::max(maxs[bucket_id], A[i]) : A[i];            mins[bucket_id] = has_num[bucket_id] ? std::min(mins[bucket_id], A[i]) : A[i];            has_num[bucket_id] = true;        }                int k = 0;        int last_max = 0;        while(k <= n){            if(has_num[k]){               last_max = maxs[k];   //排除序号为0的空桶,因为前面都是空桶,不是数据,相邻最大差是数据与数据之间的最大差,所以第一个last_max=maxs[k],               break;                //从下一个mins减去这个last_max开始找出最大的差            }           ++k;        }               while(++k <= n){            if(has_num[k]){       //只有非空桶才可以进入,所以res一直为两个非空桶的差                res = std::max(mins[k]-last_max, res);                last_max = maxs[k];   //注意更新last_max            }        }                return res;    }private:    int get_bucket_id(long long num, long long n, long long min, long long max){   //使用long long类型防止溢出        return (int)((num - min) * n / (max - min));    }};

整段程序的核心就是:

            while(++k <= n){            if(has_num[k]){       //只有非空桶才可以进入,所以res一直为两个非空桶的差                res = std::max(mins[k]-last_max, res);                last_max = maxs[k];   //注意更新last_max            }        }

这一段程序通过++k保证了在之前k的基础上加1,has_num[k]保证只有非空桶进入该条件,所以相邻两个非空桶就会进入,并计算res。我们要注意更新last_max。


0 0