桶排序

桶排序

class Solution {
public:
    class Bucket{
        public:
            bool used = false;
            int maxval = INT_MIN;
            int minval = INT_MAX;
    };

    int mins = INT_MAX, maxn = INT_MIN;

    int maximumGap(vector<int>& nums) {
        int n = nums.size();
        if (n < 2) return 0;

        for (int& x:nums) 
        {
            maxn = max(maxn, x);
            mins = min(mins, x);
        }

        // 分配桶的长度和个数是桶排序的关键
        // 在 n 个数下,形成的两两相邻区间是 n - 1 个,比如 [2,4,6,8] 这里
        // 有 4 个数,但是只有 3 个区间,[2,4], [4,6], [6,8]
        // 因此,桶长度 = 区间总长度 / 区间总个数 = (max - min) / (nums.length - 1)
        int bucketSize = max(1, (maxn-mins)/(n-1));
        
        // 上面得到了桶的长度,我们就可以以此来确定桶的个数
        // 桶个数 = 区间长度 / 桶长度
        // 这里考虑到实现的方便,多加了一个桶,为什么?
        // 还是举上面的例子,[2,4,6,8], 桶的长度 = (8 - 2) / (4 - 1) = 2
        //                           桶的个数 = (8 - 2) / 2 = 3
        // 已知一个元素,需要定位到桶的时候,一般是 (当前元素 - 最小值) / 桶长度
        // 这里其实利用了整数除不尽向下取整的性质
        // 但是上面的例子,如果当前元素是 8 的话 (8 - 2) / 2 = 3,对应到 3 号桶
        //              如果当前元素是 2 的话 (2 - 2) / 2 = 0,对应到 0 号桶
        // 你会发现我们有 0,1,2,3 号桶,实际用到的桶是 4 个,而不是 3 个
        // 透过例子应该很好理解,但是如果要说根本原因,其实是开闭区间的问题
        // 这里其实 0,1,2 号桶对应的区间是 [2,4),[4,6),[6,8)
        // 那 8 怎么办?多加一个桶呗,3 号桶对应区间 [8,10)
        int bucketNum = (maxn-mins)/bucketSize+1;
        vector<Bucket> bucket(bucketNum);

        for (int& x:nums)
        {
            int bucketIdx = (x-mins)/bucketSize;
            bucket[bucketIdx].used = true;
            bucket[bucketIdx].maxval = max(x, bucket[bucketIdx].maxval);
            bucket[bucketIdx].minval = min(x, bucket[bucketIdx].minval);
        }

        int prevBucketMax = mins, maxGap = 0;
        for (auto& bk:bucket)
        {
            if (!bk.used) continue;

            maxGap = max(maxGap, bk.minval-prevBucketMax);
            prevBucketMax = bk.maxval;
        }

        return maxGap;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值