LeetCode: Maximum Gap

思路分析

遇到这种考察排序的题目,既然要求线性时间复杂度,那么首先就要往仅有的三种线性时间复杂度排序算法上面去想。回到这个题目本身,是要求数组有序时相邻两个数的最大间隔,我们就要首先考虑,这个“最大间隔”的上下界是怎样的?

显然,如果我们固定数组中的最大值和最小值,则当数组中元素在数轴上面均匀分布时,“最大间隔”取下界,为\(\lceil\frac{A_{max}-A_{min}}{n-1}\rceil\),其中A为数组,n为数组中元素的个数;而当数组中前n-1个元素连续,最后一个元素与前面相差很远时,“最大间隔”取上界。

此时我们便不难看出,由问题定义,既然当前的无序数组中至少存在一对数字达到所谓的“最大间隔”,它们的差(绝对值)一定大于等于先前“最大间隔”的下界,那么我们只需要按照这个下界即\(\lfloor\frac{A_{max}-A_{min}}{n-1}\rfloor\),把数组所在的值域切分成n-1个桶,就一定能够保证,这对数字会被分到不同的桶中去——这就是经典的“桶排序”思想!

因此,我们只需要遍历所有的桶,记录当前桶中的最小值与上一个桶中的最大值的差,其中必然有一个会是我们所要找的“最大间隔”。这样,就能够使用线性的时间和空间复杂度来解决这个问题了。

代码

class Solution {
public:
    int maximumGap(vector<int> &num) {
        if ( num.size() < 2 ) return 0;
        int _max = num[0], _min = num[0];
        for ( int i = 1; i < num.size(); i++ ) {
            _max = max(_max, num[i]);
            _min = min(_min, num[i]);
        }
        int len = (_max - _min) / (num.size() - 1);
        if ( !len ) len = 1;
        int num_buckets = (_max - _min) / len + 1;
        int *max_val = new int[num_buckets];
        int *min_val = new int[num_buckets];
        bool *flag = new bool[num_buckets];
        for ( int i = 0; i < num_buckets; i++ ) {
            max_val[i] = INT_MIN;
            min_val[i] = INT_MAX;
            flag[i] = false;
        }
        for ( int i = 0; i < num.size(); i++ ) {
            int idx = (num[i] - _min) / len;
            flag[idx] = true;
            max_val[idx] = max(max_val[idx], num[i]);
            min_val[idx] = min(min_val[idx], num[i]);
        }
        vector<int> buckets;
        for ( int i = 0; i < num_buckets; i++ ) if ( flag[i] )
            buckets.push_back(i);
        int ans = INT_MIN;
        for ( int i = 0; i < buckets.size() - 1; i++ ) {
            ans = max(ans, min_val[buckets[i + 1]] - max_val[buckets[i]]);
        }
        return ans;
    }
};
comments powered by Disqus
Published:
2015-01-11
分类:
Tag: