164. Maximum Gap

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.

题意:给定一个未排序的数组,返回其排序后的数组中 相邻元素之差 最大的值。

比如给定:[5,9,8,3,15]

排序后为:[3,5,8,9,15],相邻元素之差最大的是15-9=6,返回6。

复杂度要求:时间空间均为O(n)。

那么,线性的排序算法有哪些?计数排序、基数排序、桶排序。

下面用桶排序实现,这也是leetcode上给出的参考解法,我直接copy过来:


Suppose there are N elements and they range from A to B.

Then the maximum gap will be no smaller than ceiling[(B - A) / (N - 1)]

Let the length of a bucket to be len = ceiling[(B - A) / (N - 1)], then we will have at most num = (B - A) / len + 1 of bucket

for any number K in the array, we can easily find out which bucket it belongs by calculating loc = (K - A) / len and therefore maintain the maximum and minimum elements in each bucket.

Since the maximum difference between elements in the same buckets will be at most len - 1, so the final answer will not be taken from two elements in the same buckets.

For each non-empty buckets p, find the next non-empty buckets q, then q.min - p.max could be the potential answer to the question. Return the maximum of all those values.

根据上面的思路,得到代码如下:

class Solution {
public:
    int maximumGap(vector<int> &num) {
       if (num.size() < 2) return 0;
        //遍历一遍,找出最大最小值
        int maxNum = num[0];
        int minNum = num[0];
        for (int i : num) {
            maxNum=max(maxNum,i);
            minNum=min(minNum,i);
        }
        // 每个桶的长度len,向上取整所以加+
        int len = (maxNum - minNum) / num.size() + 1;
        
        //桶的个数:(maxNum - minNum) / len + 1,每个桶里面存储属于该桶的最大值和最小值即可,注意这里的最大最小值是局部的
        vector<vector<int>> buckets((maxNum - minNum) / len + 1);
        for (int x : num) {
            int i = (x - minNum) / len;
            if (buckets[i].empty()) {
                buckets[i].reserve(2);
                buckets[i].push_back(x);
                buckets[i].push_back(x);
            } else {
                if (x < buckets[i][0]) buckets[i][0] = x;
                if (x > buckets[i][1]) buckets[i][1] = x;
            }
        }
        //gap的计算,For each non-empty buckets p, find the next non-empty buckets q, return min( q.min - p.max )
        int gap = 0;
        int prev = 0;
        for (int i = 1; i < buckets.size(); i++) {
            if (buckets[i].empty()) continue;
            gap = max(gap, buckets[i][0] - buckets[prev][1]);
            prev = i;
        }
        return gap;
    }
};

2015.10.8号更新

------------------------------------

10.8号重新看这道题的证明以及参考答案的时候,发现有几个问题。

1.为什么len是 (maxNum - minNum) / num.size() + 1;而不是 ceil((maxNum - minNum) / ((double)num.size() -1))和 (maxNum - minNum) / (num.size() -1)+1

首先为什么不是((maxNum - minNum) / ((double)num.size() -1))呢,因为我们至少应该让len为1!!当输出的数组为{1,1,1,1}时候,如果让len=ceil((maxNum - minNum) / ((double)num.size() -1)),我们会发现len=0,那么当我们用(num-minNum)/len求得num属于第几个桶时,就会出现除0的错误。所以我们要写成一个式子+1的形式。

那既然不写成第一种形式,那又为何不写成第二种形式呢,也就是len=(maxNum - minNum) / (num.size() -1)+1。首先,要满足maxGap不在同一个桶内的元素中取得,桶的大小至少应该为 ceiling[(B - A) / (N - 1)],换句话说,桶的上界为 ceiling[(B - A) / (N - 1)],下界却没有规定!!官方答案的意思是说,“只要这个len不超过ceiling[(B - A) / (N - 1)],就能保证maximum gap不在一个bucket里”。但是这个length取得小一点可不可以呢?当然可以,len小的话更加能确保上述条件,只是这样的话bucket数更多,更耗内存而已。如果你有8G以上的内存,length恒取为1都没有问题。官方给出的这个表达式不过是“最省内存”的方法。所以我们可以明白,如果len可以写成 (maxNum - minNum) / (num.size() -1)+1,那写成(maxNum - minNum) / num.size() + 1也一定不会错。不过代码作者,为什么没有写成(maxNum - minNum) / (num.size() -1)+1呢?个人的推测,是因为+1的原因,作者担心+1之后,(maxNum - minNum) / (num.size() -1)+1在某些时候会大于ceiling[(B - A) / (N - 1)],所以对(maxNum - minNum) / (num.size() -1)+1进行了收缩。

2.为什么桶的个数写为(maxNum - minNum) / len + 1,因为对于minNum肯定在第0个桶,对于maxNum放在第(maxNum - minNum) / len就好了,所以为(maxNum - minNum) / len+1个桶。

3.为什么prev的初始值为0,因为对于第0个桶来说,因为minNum的存在,所以一定是非空的!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值