日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

云漫圈 | 寻找无序数组的第k大元素

發布時間:2024/9/27 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 云漫圈 | 寻找无序数组的第k大元素 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

戳藍字“CSDN云計算”關注我們哦!


者:小灰

來源:程序員小灰

???本期封面作者:泰勒太樂

? ? ? ???


—————? 第二天? —————




題目是什么意思呢?比如給定的無序數組如下:



如果 k=6,也就是要尋找第6大的元素,這個元素是哪一個呢?


顯然,數組中第一大的元素是24,第二大的元素是20,第三大的元素是17 ......?第6大的元素是9。



方法一:排序法

這是最容易想到的方法,先把無序數組從大到小進行排序,排序后的第k個元素,自然就是數組中的第k大元素。






方法二:插入法

維護一個長度為k的數組A的有序數組,用于存儲已知的k個較大的元素。

接下來遍歷原數組,每遍歷到一個元素,和數組A中最小的元素相比較,如果小于等于數組A的最小元素,繼續遍歷;如果大于數組A的最小元素,則插入到數組A中,并把曾經的最小元素“擠出去”。


比如k=3,先把最左側的7,5,15三個數有序放入數組A當中,代表當前最大的三個數。


這時候,遍歷到3, 由于3<5,繼續遍歷。


接下來遍歷到17,由于17>5,插入到數組A的合適位置,類似于插入排序,并把原先最小的元素5“擠出去”。


繼續遍歷原數組,一直遍歷到數組的最后一個元素......


最終,數組A中存儲的元素是24,20,17,代表著整個數組中最大的3個元素。此時數組A中的最小的元素17就是我們要尋找的第k大元素。




————————————







什么是二叉堆?不太了解的小伙伴可以先看看這一篇:漫畫:什么是二叉堆?


簡而言之,二叉堆是一種特殊的完全二叉樹,它包含大頂堆和小頂堆兩種形式。


其中小頂堆的特點,是每一個父節點都大于等于自己的子節點。要解決這個算法題,我們可以利用小頂堆的特性。




方法三:小頂堆法

維護一個容量為k的小頂堆,堆中的k個節點代表著當前最大的k個元素,而堆頂顯然是這k個元素中的最小值。

遍歷原數組,每遍歷一個元素,就和堆頂比較,如果當前元素小于等于堆頂,則繼續遍歷;如果元素大于堆頂,則把當前元素放在堆頂位置,并調整二叉堆(下沉操作)。

遍歷結束后,堆頂就是數組的最大k個元素中的最小值,也就是第k大元素。


假設k=5,具體的執行步驟如下:


1.把數組的前k個元素構建成堆。



2.繼續遍歷數組,和堆頂比較,如果小于等于堆頂,則繼續遍歷;如果大于堆頂,則取代堆頂元素并調整堆。


遍歷到元素2,由于 2<3,所以繼續遍歷。



遍歷到元素20,由于 20>3,20取代堆頂位置,并調整堆。





遍歷到元素24,由于 24>5,24取代堆頂位置,并調整堆。





以此類推,我們一個一個遍歷元素,當遍歷到最后一個元素8的時候,小頂堆的情況如下:



3.此時的堆頂,就是堆中的最小值,也就是數組中的第k大元素。




這個方法的時間復雜度是多少呢?


1.構建堆的時間復雜度是 O(k)

2.遍歷剩余數組的時間復雜度是O(n-k)

3.每次調整堆的時間復雜度是 O(logk)


其中2和3是嵌套關系,1和2,3是并列關系,所以總的最壞時間復雜度是O((n-k)logk + k)。當k遠小于n的情況下,也可以近似地認為是O(nlogk)。



這個方法的空間復雜度是多少呢?


剛才我們在詳細步驟中把二叉堆單獨拿出來演示,是為了便于理解。但如果允許改變原數組的話,我們可以把數組的前k個元素“原地交換”來構建成二叉堆,這樣就免去了開辟額外的存儲空間。


因此,方法的空間復雜度是O(1)



  • /**

  • * 尋找第k大的元素

  • * @param array ?待調整的堆

  • * @param k ?第幾大

  • */

  • public static int findNumberK(int[] array, int k){

  • ? ?//1.用前k個元素構建小頂堆

  • ? ?buildHeap(array, k);

  • ? ?//2.繼續遍歷數組,和堆頂比較

  • ? ?for(int i=k; i<array.length;i++){

  • ? ? ? ?if(array[i] > array[0]){

  • ? ? ? ? ? ?array[0] = array[i];

  • ? ? ? ? ? ?downAdjust(array, 0, k);

  • ? ? ? ?}

  • ? ?}

  • ? ?//3.返回堆頂元素

  • ? ?return array[0];

  • }


  • /**

  • * 構建堆

  • * @param array ?待調整的堆

  • * @param length ?堆的有效大小

  • */

  • private static void buildHeap(int[] array, int length) {

  • ? ?// 從最后一個非葉子節點開始,依次下沉調整

  • ? ?for (int i = (length-2)/2; i >= 0; i--) {

  • ? ? ? ?downAdjust(array, i, length);

  • ? ?}

  • }


  • /**

  • * 下沉調整

  • * @param array ? ? 待調整的堆

  • * @param index ? ?要下沉的節點

  • * @param length ? ?堆的有效大小

  • */

  • private static void downAdjust(int[] array, int index, int length) {

  • ? ?// temp保存父節點值,用于最后的賦值

  • ? ?int temp = array[index];

  • ? ?int childIndex = 2 * index + 1;

  • ? ?while (childIndex < length) {

  • ? ? ? ?// 如果有右孩子,且右孩子小于左孩子的值,則定位到右孩子

  • ? ? ? ?if (childIndex + 1 < length && array[childIndex + 1] < array[childIndex]) {

  • ? ? ? ? ? ?childIndex++;

  • ? ? ? ?}

  • ? ? ? ?// 如果父節點小于任何一個孩子的值,直接跳出

  • ? ? ? ?if (temp <= array[childIndex])

  • ? ? ? ? ? ?break;

  • ? ? ? ?//無需真正交換,單向賦值即可

  • ? ? ? ?array[index] = array[childIndex];

  • ? ? ? ?index = childIndex;

  • ? ? ? ?childIndex = 2 * childIndex + 1;

  • ? ?}

  • ? ?array[index] = temp;

  • }



  • public static void main(String[] args) {

  • ? ?int[] array = new int[] {7,5,15,3,17,2,20,24,1,9,12,8};

  • ? ?System.out.println(findNumberK(array, 5));

  • }



  • 方法四:分治法

    大家都了解快速排序,快速排序利用分治法,每一次把數組分成較大和較小的兩部分。

    我們在尋找第k大元素的時候,也可以利用這個思路,以某個元素A為基準,把大于于A的元素都交換到數組左邊,小于A的元素都交換到數組右邊。


    比如我們選擇以元素7作為基準,把數組分成了左側較大,右側較小的兩個區域,交換結果如下:



    包括元素7在內的較大元素有8個,但我們的k=5,顯然較大元素的數目過多了。于是我們在較大元素的區域繼續分治,這次以元素12位基準:




    這樣一來,包括元素12在內的較大元素有5個,正好和k相等。所以,基準元素12就是我們所求的。


    這就是分治法的大體思想,這種方法的時間復雜度甚至優于小頂堆法,可以達到O(n)。有興趣的小伙伴可以嘗試用代碼實現一下。



    1.微信群:

    添加小編微信:color_ld,備注“進群+姓名+公司職位”即可,加入【云計算學習交流群】,和志同道合的朋友們共同打卡學習!


    2.征稿:

    投稿郵箱:liudan@csdn.net;微信號:color_ld。請備注投稿+姓名+公司職位。



    推薦閱讀

    • 有問有答 | 分布式服務框架精華問答

    • 深入理解與應用Hadoop中的MapReduce

    • 等了20年的物聯網,這次真的會成功嗎?

    • 云要聞 | 騰訊在華南建云計算基地;致敬Larry Roberts

    • 網友們票選的2018 Best Paper,你pick誰?

    • 程序員有話說 | 大專生畢業 6 年月薪 3W+:不從眾也不普通

    • Windows 10 終于干掉了 Windows 7!

    • 比特幣拒絕第340次“被死亡”


    程序員搶票的正確姿勢 ↓↓交朋友還能搶票?


    為交流學習,請備注搶票+姓名+公司職位


    點擊“閱讀原文”,打開 CSDN App 閱讀更貼心!

    喜歡就點擊“好看”吧!

    總結

    以上是生活随笔為你收集整理的云漫圈 | 寻找无序数组的第k大元素的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。