首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

LeetCode 23 合併 K 個有序鏈表:優先隊列(最小堆)O(N log k) 最優解

     編輯:關於C++

題目描述

合併 k 條已排序的鏈表,返回合併後的有序鏈表。分析時間複雜度。

方法一:兩兩合併(超時)

依次將當前結果與下一條鏈表合併,時間 O(k × N),其中 N 為總節點數。LeetCode 測試用例大時會 TLE。

// TLE 版本
ListNode* mergeKLists(vector<ListNode*> &lists) {
    ListNode *head = nullptr;
    for (auto list : lists) head = mergeTwoLists(head, list);
    return head;
}

方法二:最小優先隊列(最小堆) - AC

核心思想

  1. 將 k 條鏈表的頭節點放入最小堆
  2. 每次取出堆頂最小節點,接入結果鏈表
  3. 若該節點有 next,將 next 入堆
  4. 堆空時結束

堆中始終維護 k 個候選最小節點,每次操作 O(log k),總節點 N,總體 O(N log k)。

AC 代碼

#include <iostream>
#include <queue>
#include <vector>
using namespace std;

struct ListNode {
    int val; ListNode *next;
    ListNode(int x) : val(x), next(nullptr) {}
};

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*> &lists) {
        ListNode dummy(-1);
        ListNode *tail = &dummy;
        
        // 自定義比較器:最小堆
        struct Compare {
            bool operator()(ListNode* a, ListNode* b) { return a->val > b->val; }
        };
        priority_queue<ListNode*, vector<ListNode*>, Compare> pq;
        
        // 初始化:非空鏈表頭節點入堆
        for (auto node : lists) if (node) pq.push(node);
        
        while (!pq.empty()) {
            ListNode *cur = pq.top(); pq.pop();
            tail->next = cur;
            tail = cur;
            if (cur->next) pq.push(cur->next);
        }
        return dummy.next;
    }
};

// 輔助:構建鏈表、輸出、主函數測試(略)

複雜度分析

方法時間空間備註
兩兩合併O(kN)O(1)k 大時退化
分治合併O(N log k)O(log k)遞歸棧空間
最小堆O(N log k)O(k)推薦,代碼簡潔

關鍵點

  • 使用 dummy 節點簡化頭節點處理
  • 自定義 Compare 實現最小堆(默認 priority_queue 為最大堆)
  • 僅將非空節點入堆,避免空指針
  • 每個節點進出堆各一次,共 2N 次堆操作

運行結果截圖

AC 運行截圖

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved