【Leet Code】164. Maximum Gap---Hard

本文介绍了一种线性时间复杂度的算法来找出无序数组排序后相邻元素的最大差值,包括桶排序的原理及实现。

Given an unsorted array, find the maximum difference between the successive elements in its sorted form.

Try to solve it in linear time/space.

Return 0 if the array contains less than 2 elements.

You may assume all elements in the array are non-negative integers and fit in the 32-bit signed integer range.

题目大意:在一个无序的数组中,求这个数组排序完以后,相邻的两个数最大差值,要求保证O(n)的复杂度。

思路:  本题目仅需要2步:

1)排序数组

2)求排序后的数组中相邻元素差值的最大值。

难点:对步骤1),怎么在线性时间/空间中对数组排序。

求解算法:

桶排序:

算出相邻两个桶之间的最大差值;

如果是平均分布,则桶的数目和元素的数目相同时,排序时间的复杂度是O(n);

假设桶的个数和元素的数目相同,若是平均分布,则每个桶有一个数,而若某个桶里有两个以上的元素时,此时必有至少一个桶是空桶,那么最大间隔有可能落在空桶的相邻的两个桶存储的数之间,最大间隔不会落在同一个桶的数里,因此我们不需要对每一个桶再排一次序,只需要记录同一个桶的最大着和最小值,算出前一个有最大值的桶和后一个有最小值的桶之差,该值可能是最大间隔。

步骤:

1)算好用的桶的个数,用最大元素和最小元素算出平均间隔,记录在平均间隔上的最大值和最小值;

2)算出前一个间隔里的最大值和后一个间隔里的最小值之差,取最大的一个。


代码实现:

class Solution {
public:
    int maximumGap(vector<int>& nums) {
        int n = nums.size();
        if (n < 2) return 0;
        
        //1. 算出用的桶数:取平均间隔,再用最大值和最小值之差除以间隔,得到桶数
        // 因为假设所有值都是平均分布的时候,如此取桶数可得时间复杂度是0(n)
        auto lu = minmax_element(nums.begin(), nums.end());
        int l = *lu.first, u = *lu.second;
        int agGap = max((u - l) / (n - 1), 1); //平均间隔
        int bucketCount = (u - l) / agGap + 1;
        
        //2. 记录每个桶的最大值和最小值
        vector<int> bucketsMin(bucketCount, INT_MAX);
        vector<int> bucketsMax(bucketCount, INT_MIN);
        for (int num : nums) {
            int k = (num - l) / agGap;
            if (num < bucketsMin[k]) bucketsMin[k] = num;
            if (num > bucketsMax[k]) bucketsMax[k] = num;
        }
        
        //3. 算出最大间隔
        int i = 0, j; 
        int result = bucketsMax[0] - bucketsMin[0];
        while (i < bucketCount) {
            j = i + 1;
            //忽略空桶
            while (j < bucketCount && bucketsMin[j] == INT_MAX && bucketsMax[j] == INT_MIN)
                j++;
            if (j == bucketCount) break;
            result = max(result, bucketsMin[j] - bucketsMax[i]);
            i = j;
        }
        return result;
    }
};



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值