桶排序的应用

  1. 题目
    在一个无序数组中,求取有序之后相邻数差值最大的在一个无序数组中,求取有序之后相邻数差值最大的
    要求:时间复杂度为O(n),且存在数据范围特别大(即不允许使用桶排序)
  2. 解法:只是借鉴了桶的概念,而并没有使用桶排序来求取。这一次是取决于给定的数组中的元素个数,过程如下:
    (1)数组的大小是N,需要准备N+1个桶来划分
    (2)求取数组中的最大值maxn和最小值minn,并且保证最小值一定在0号桶,最大值一定在N号桶
    (3)将(maxn-minn)/(N+1)作为一个区域划分,可以称为range,将数组中的数根据range填入相应的桶中
    (4)申请N+1个桶,维护三个数组作为标记,标记桶中的最大值和最小值,以及该桶是否为空桶。
    同时数组中的元素要进入的桶编号BID = (num-min)*len/(max-min)
    (5)由于申请了N+1个桶,所以至少有一个桶是空的,那么相邻的数可能在一个桶中,也有可能在不同的桶中。在同一个桶中的任何两个数的差值都不会大于值range,并且空桶两边的非空桶,即左边桶的max值和右边桶的min值肯定大于range。可知MaxGap必然来自不同的桶中。所以扫一遍相邻的非空桶的(右边桶)min值减去(左边桶)max值 = ans,取ans的max值
注意一点:最大差值未必来自空桶两则的非空桶,空桶两侧只是用于证明一下桶内差必然<=range
如下图:

在这里插入图片描述
3. 举个例子

给定数组arr[5] = {3,4,0,9,10}
可知min = 0, max = 10 
则range = (max-min)/(N+1) = 5/3
所以区间划分是如下图:(保证min在0号桶,max在N号桶)

在这里插入图片描述
4. 代码

#include<bits/stdc++.h>
using namespace std;

//使用long类型使为了避免相乘的时候数据溢出
int BucketID(long num, long len, long maxn, long minn){
    return (int)((num-minn)*len/(maxn - minn));
}

int MaxGap(int a[],int len){
    int minn = INT_MAX;
    int maxn = INT_MIN;
    for(int i = 0; i < len; ++i){
        minn = min(minn,a[i]);
        maxn = max(maxn,a[i]);
    }
    if(maxn == minn)
        return 0;
    bool hasNum[len+1] = {false};
    int  minNum[len+1] = {0};
    int  maxNum[len+1] = {0};
    int buckId = 0;
    for(int i = 0; i < len; ++i){
        buckId = BucketID(a[i],len,maxn,minn);
        minNum[buckId] = hasNum[buckId] ? min(minNum[buckId],a[i]) : a[i];
        maxNum[buckId] = hasNum[buckId] ? max(maxNum[buckId],a[i]) : a[i];
        hasNum[buckId] = true;
    }
    int res = 0;
    int lastMax = maxNum[0];
    for(int i = 1; i <= len; ++i){
        if(hasNum[i]){
            res = max(res,minNum[i]-lastMax);
            lastMax = maxNum[i];
        }
    }
    return res;
}



int main()
{
    int a[5] = {0,3,4,9,10};
    int ans = MaxGap(a,5);
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/bryant_xw/article/details/87868383