有道算法題--排序之桶排序實現求排序後相鄰最大差值問題

前言

一直誤覺得寫文章太耗費費時間,昨日爲尊敬高貴帥氣逼人的導師所一語驚醒(未一舉成名之日,毫不提尊師名諱,嗯,沒錯),分享纔是程序員最快的提高; 今天開始,作不到多寫多練,就不是誠實善良的南方小菜啦程序員

不廢話,直接進入主題算法

預備知識

桶排序(Bucket sort)或所謂的箱排序,是一個排序算法,工做的原理是將數組分到有限數量的桶裏。每一個桶再個別排序(有可能再使用別的排序算法或是以遞歸方式繼續使用桶排序進行排序),最後依次把各個桶中的記錄列出來記獲得有序序列。桶排序是鴿巢排序的一種概括結果。當要被排序的數組內的數值是均勻分配的時候,桶排序使用線性時間(Θ(n))。但桶排序並非比較排序,他不受到O(n log n)下限的影響。數組

算法穩定性:假定在待排序的記錄序列中,存在多個具備相同的關鍵字的記錄,若通過排序,這些記錄的相對次序保持不變,即在原序列中,A1=A2,且A1在A2以前,而在排序後的序列中A1仍在A2以前,則稱這種排序算法是穩定的;不然稱爲不穩定的。bash

--------------------------- 我是分割線--------------------------------——————————————————————————————————ui

以上是教材定義,非小菜所講,其實一個概念都可用幾個特性來描述,對於桶排序,簡單來講有以下特性:this

  1. 非基於比較
  2. 運用到了桶的概念
  3. 時間複雜度O(N) 空間複雜度O(N)
  4. 不廣泛,存在瓶頸,具備穩定性

    ???????????????????????????????????

什麼鬼?啥叫桶?咋就時間空間複雜度O(N)了?看客莫急,這樣劃分咱就能夠一一破之啦(在下面的題目中會更加體現);spa

特性解釋

  1. 非基於比較
    一提到排序,你們腦海裏必然不自覺浮現出ifelse以及C語言老師神祕莫測的微笑,是的,不管是古老的冒泡、玄學的歸併、撲克牌(發哥?)式插入等等等,都不可避免的進行了元素與元素之間的比較,並不是很差,只是百家爭鳴,思想的萬花筒讓桶排序這一方式出現,他的實現思想並非比較,而是分治,即進行範圍區間劃分,而後將數據按規律放入,這樣放置好了以後,因爲桶自己就存在順序,也就天然而然地實現了處理數據的必定規律排序,卻沒有用到彼此之間的比較

  2. 何爲桶?其實就是一個容器,他能夠是鏈表、雙向鏈表、集合等等等,這個容器的特徵在於,他保存了一個狀態(即上述的一段區間)下出現的詞頻(即你須要的這個區間內的數據)
  3. 複雜度計算
    當你要建立桶,必然須要耗費額外的空間,長度爲N===》空間複雜度O(N) 而以下上述,按狀態依次放置數據於桶中,須要遍歷數據====》時間複雜度O(N)
    • 穩定性:簡單來講,一個蘿蔔一個坑,數據對着已排好的桶進行放置,必然穩定;
    • 瓶頸:與被排序的實際數據狀態有關,因此不具備廣泛性

題解

重點來了,題解纔是最好的理解code

請聽題cdn

  • 給定一個數組,求若是排序以後,相鄰兩個數的最大差值,要求時間複雜度O(N),且要求不能用非基於比較的排序
解題思路
  1. 非基於比較 ===== 這已是很明顯的提示咱們要用桶排序了
  2. 要求時間複雜度O(N) ====== 桶!!!!
  3. 假設有N個數據的數組arr,其中最大值max,最小值min,
    1. 數據對應桶的下標的計算:parseInt((num-min)*N/max-min)
    2. 定義兩個數組容器,分別存儲對應桶的min和max
    3. 遍歷非空桶min與下一個非空桶的max的差值,最大差值即爲解
代碼實現(我的習慣多寫註釋,因此你們能夠參考一下注釋內容)
// 給定一個數組,求若是排序以後,相鄰兩個數的最大差值,要求時間複雜度O(N),且要求不能用非基於比較的排序

class MaxGap {
    constructor(){

    }
    
    getMax(arr){
        if(arr == null || arr.length<2) return 0;
        // 數組長度 數組中最大最小值
        let len = arr.length,min= arr[0],max= arr[0];
        // 桶中是否有數 每一個桶中的最大值 最小值
        let hasNum=[],maxs=[],mins=[];
        // 遍歷數組取最大最小值
        for(let i = 0; i<len;i++){
          
            min = Math.min(min,arr[i]);
            max = Math.max(max,arr[i]);
            // console.log(min,max)
        }
        if(min == max) return 0;
        let bid = 0;
        // 循環遍歷 將數放在對應範圍的桶中 只保留桶中數的max和min 而且將桶的狀態改成true
        for(let i = 0;i<len;i++){
            bid = this.bucket(arr[i],len,min,max);
            mins[bid] = hasNum[bid] ? Math.min(mins[bid],arr[i]) : arr[i];
            maxs[bid] = hasNum[bid] ? Math.max(maxs[bid],arr[i]) : arr[i];
            hasNum[bid] = true;
            // console.log(hasNum)
        }
        // 最大差值
        let res = 0;

        let lastMax = maxs[0];
        let i = 1;
        // console.log(hasNum)
        for(;i<=len;i++){
            // 遍歷非空桶min與下一個非空桶的max的差值,最大差值即爲res   
            // 注意,空桶只是殺死了同一個桶中的值的差值不可能爲最大,而並不能保證最大差值必定在空桶附近出現
            if(hasNum[i]){
                res = Math.max(res, mins[i] - lastMax);
                lastMax = maxs[i]
            }
        }
        console.log(mins,maxs)
        return res;

    }

    /**
     * 求出num對應桶的索引
     * @param {目標數} num 
     * @param {數組長度} len 
     * @param {數組最小值} min 
     * @param {數組最大值} max 
     */
    bucket(num,len,min,max){
        // console.log(num,len,min,max)
        // console.log((num - min) * len / (max - min))
        return parseInt((num - min) * len / (max - min));
    }


}
console.log(new MaxGap().getMax([1,3,100,9,8]));

複製代碼
相關文章
相關標籤/搜索