[LeetCode]problem 164. Maximum Gap

TAG

桶排序

浮點數不精確

link

方法

一眼看過去完全不知道該怎麼做。

看了題解覺得很高端的樣子,再後來多看了下,發現本質其實就是一個線性時間排序的問題!

線性時間排序,有計數排序、桶排序、基數排序。

計數排序時間複雜度與最大值與最小值差值有關。桶排序可以分桶,如果能夠把問題轉化到只計算桶間間距,那麼時間複雜度就能是與輸入個數成線性的了。基數排序沒有嘗試。

這道題官方題解是使用桶排序,每個桶只記錄落到這個桶的最大值與最小值。爲了使相鄰兩個數的最大間隔只存在兩個連續非空桶間(前一個數是前一個桶的最大值,後一個數是後一個桶的最小值),必須保證桶的個數大於等於輸入數據的個數

爲何?利用類鴿巢原理,n個數,n個桶,要麼每個桶中一個數,要麼至少有一個桶爲空(暫且這麼瞎稱呼,正規的鴿巢原理是n+1個數,n個桶,則必然有一個桶至少有2個數)。如果每個桶中一個數,則連續非空桶間的最大間隔就是連續兩個數的最大間隔,成立。如果至少一個桶爲空,那麼必然有兩個連續的數,他們之間的間隔至少跨越了一個桶(表示的間隔),而在一個桶內的數,他們的間隔必然不會大於一個桶表示的間隔。

問題就變得簡單了。

然而還是遇到了坑——

設桶的個數爲輸入數據個數。當輸入數據只有2個時,桶的個數爲2;桶的間隔計算公式寫的是:

interval = static_cast<int>( 
             ceil(
                  ( maxVal - minVal ) / float(nrBuckets - 1)
                 )    
            ) ;

按理說肯定沒有錯的… minVal 必然落在第一個桶,maxVal落在第二個桶 ((maxVal - minVal) / interval == 1 ?),然而卻錯了。

遇到了這個Case: [2,99999999],既然發現 static_cast<int>( ceil((9999999-2)/float(2-1)) ) 值爲10^8,不應該是99999997嗎!!

浮點數就這麼不準嗎…

遇到這個坑後,當時解決辦法是用了精確ceil.. 所以精確,就是先判斷能夠整除(模爲0),如果能則直接整數除法,如果不能,則整數除法再加1,這樣因爲是整數除法,所以就ok了。

 int exactCeilDivide(int dividend, int divisor)
    {
        if(dividend % divisor == 0){ return dividend / divisor ;}
        else {  return dividend / divisor + 1;}
    }

後來,我把桶設爲輸入數據數+1,即使使用ceil函數也不會有問題了…

不過,或許不遇到這個坑,也不會注意到這個問題吧。

代碼

class Solution {
public:
    int maximumGap(vector<int>& nums) {
        size_t nrNum = nums.size() ; 
        if(nrNum < 2) return 0 ;
        int minVal = *min_element(nums.cbegin(), nums.cend());
        int maxVal = *max_element(nums.cbegin(), nums.cend());
        if(minVal == maxVal) return 0; // edge condition

        int nrBuckets = nrNum + 1;
        int bucketRangeVal = static_cast<int>( ceil( (maxVal-minVal)/float(nrBuckets-1)  ) );
        vector<bucket> buckets(nrBuckets);
        // dispatch
        for(int num : nums)
        {
            int bucketIdx = ( num - minVal ) / bucketRangeVal ;
            buckets[bucketIdx].fill(num);
        }
        // find max grap (only exists in different bucket)
        int maxGap = 0;
        auto aheadIter = buckets.begin() ; // min val must in the first bucket
        while(true)
        {
            auto nextFilledIter = aheadIter + 1 ;
            while(nextFilledIter < buckets.end() && !nextFilledIter->isFilled)
            {
                ++nextFilledIter;
            }
            if(nextFilledIter >= buckets.end()) break;
            maxGap = max(maxGap, get_bucket_gap(*aheadIter, *nextFilledIter));
            aheadIter = nextFilledIter;
        }
        return maxGap;
    }
private :
    struct bucket
    {
        int minVal;
        int maxVal;
        bool isFilled;
        bucket() : isFilled(false){}
        void fill(int val)
        {
            if(!isFilled)
            {
                minVal = maxVal = val;
                isFilled = true;
            }
            else
            {
                minVal = min(minVal, val);
                maxVal = max(maxVal, val);
            }
        }
    };
    int get_bucket_gap(const bucket &ahead, const bucket &bebind)
    {
        return (bebind.minVal - ahead.maxVal);
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章