再談Heap(堆)的妙用

好久沒更新了篮昧,今天我又來了。一直看我文章的朋友可能會發(fā)現(xiàn)民傻,我之前多次提到堆這個數(shù)據(jù)結(jié)構(gòu)胰默,它可以幫助我們快速地在一堆數(shù)據(jù)中场斑,找到符合某個條件的最大或者最小的元素。今天我們還是要來談?wù)撍J穑瑳]辦法漏隐,它就是這么強(qiáng)大又好用。

來看這樣一道題目:給定K個排序好的鏈表奴迅,排序好合并到一個列表中去青责。

示例 1:
輸入: L1=[2, 6, 8], L2=[3, 6, 7], L3=[1, 3, 4]
輸出: [1, 2, 3, 3, 4, 6, 6, 7, 8]
示例 2:
輸入: L1=[5, 8, 9], L2=[1, 7]
輸出: [1, 5, 7, 8, 9]

拿到這道題的第一感覺似乎也不是很難嘛,我們可以把所有元素加到一個列表里面去然后再排序取具,時間復(fù)雜度也不過是O(N?logN)脖隶。這里N是K個鏈表所有元素之和。

不過這么做的話暇检,其實(shí)鏈表們排沒排序都一樣产阱,既然題目告訴我們鏈表是排序好的,那它肯定是更優(yōu)解法的重要條件块仆。我們得想辦法利用好這個條件构蹬。我們想要讓最終的列表排好序,那肯定要把所有元素里最小的元素放在前面悔据。既然給我們的K個鏈表都是排好序的庄敛,那我們只要比較它們的第一個元素就能得到最終列表的最小元素里。拿到最小元素我們就添加到最終列表里科汗,按照這個思路藻烤,我們在每一步都可以拿到K個鏈表中的最小元素,最后得到我們想要的結(jié)果头滔。

那說到在K個元素中找最小的元素怖亭,我們又想到堆了。那我們再來盤一下用堆我們該怎么做:

  1. 把每個鏈表第一個元素插入到最小堆
  2. 從堆中取出最小的元素添加到結(jié)果列表中
  3. 再從拿出去的元素所在的那個鏈表中取出下一個元素放到堆中
  4. 重復(fù)第2步跟第3步坤检,我們可以保證所有元素添加到了結(jié)果列表中且有序

就拿第一個例子來說依许,我們再來詳細(xì)討論一下這個過程。
給定的鏈表: L1=[2, 6, 8], L2=[3, 6, 7], L3=[1, 3, 4]

  1. 在從每個鏈表中取出第一個元素時缀蹄,我們的堆是這樣的:


  2. 我們會取出位于堆頂?shù)脑厍吞尤氲胶喜⒌牧斜碇校缓蟀堰@個元素所在鏈表中的的下一個元素加入到堆中:


  3. 那么缺前,我們再次把堆頂?shù)脑厝〕龇诺浇Y(jié)果列表中蛀醉,把下一個元素添加到堆中:


  4. 重復(fù)上面的步驟,取出堆頂元素加入到結(jié)果列表中衅码,再把它的下一個元素加入到堆中拯刁。這里有兩個3,可以隨便選逝段,但是要注意選了哪個就把哪個的下一個元素加到堆中垛玻,這個次序很重要割捅。



    最終我們就能得到一個排序好的列表啦!

public static ListNode merge(ListNode[] lists) {
    PriorityQueue<ListNode> minHeap = new PriorityQueue<ListNode>((n1, n2) -> n1.value - n2.value);

    // 把第一個元素添加到堆
    for (ListNode root : lists)
      if (root != null)
        minHeap.add(root);

    // 從最小堆中取出最小的元素并加入到結(jié)果中
    // 如果它在鏈表中還有下一個元素帚桩,那么把它的這個下一個元素添加到堆中
    ListNode resultHead = null, resultTail = null;
    while (!minHeap.isEmpty()) {
      ListNode node = minHeap.poll();
      if (resultHead == null) {
        resultHead = resultTail = node;
      } else {
        resultTail.next = node;
        resultTail = resultTail.next;
      }
      if (node.next != null)
        minHeap.add(node.next);
    }

    return resultHead;
  }

看看亿驾,這個問題有了堆這個數(shù)據(jù)結(jié)構(gòu)變得格外簡單,復(fù)雜度也得到了優(yōu)化账嚎!這里時間復(fù)雜度在O(N?logK)莫瞬,而空間復(fù)雜度在O(K)。這就是我們常聽到的多路歸并算法的核心思想郭蕉,以后再看到類似題目知道該怎么辦了吧疼邀?

最后的最后,我再強(qiáng)調(diào)下復(fù)習(xí)一下常見的數(shù)據(jù)結(jié)構(gòu)的重要性召锈,會對我們解題大有幫助旁振。就拿這道題來說,思路其實(shí)很簡單涨岁,但是如果不知道或者忘了堆的用法规求,這道題大概率只能想到把所有元素加入結(jié)果列表再排序,豈不可惜卵惦?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市瓦戚,隨后出現(xiàn)的幾起案子沮尿,更是在濱河造成了極大的恐慌,老刑警劉巖较解,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件畜疾,死亡現(xiàn)場離奇詭異,居然都是意外死亡印衔,警方通過查閱死者的電腦和手機(jī)啡捶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奸焙,“玉大人瞎暑,你說我怎么就攤上這事∮敕” “怎么了了赌?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長玄糟。 經(jīng)常有香客問我勿她,道長,這世上最難降的妖魔是什么阵翎? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任逢并,我火速辦了婚禮之剧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘砍聊。我一直安慰自己背稼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布辩恼。 她就那樣靜靜地躺著雇庙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪灶伊。 梳的紋絲不亂的頭發(fā)上疆前,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機(jī)與錄音聘萨,去河邊找鬼竹椒。 笑死,一個胖子當(dāng)著我的面吹牛米辐,可吹牛的內(nèi)容都是我干的胸完。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼翘贮,長吁一口氣:“原來是場噩夢啊……” “哼赊窥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起狸页,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤锨能,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后芍耘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體址遇,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年斋竞,在試婚紗的時候發(fā)現(xiàn)自己被綠了倔约。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡坝初,死狀恐怖浸剩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鳄袍,我是刑警寧澤乒省,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站畦木,受9級特大地震影響袖扛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一蛆封、第九天 我趴在偏房一處隱蔽的房頂上張望唇礁。 院中可真熱鬧,春花似錦惨篱、人聲如沸盏筐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽类垦。三九已至她肯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間啦鸣,已是汗流浹背盈简。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工碑诉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留常遂,地道東北人纳令。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像克胳,于是被迫代替她去往敵國和親平绩。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359