题目

合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。

示例:

输入:

1
2
3
4
5
[
  1->4->5,
  1->3->4,
  2->6
]

输出: 1->1->2->3->4->4->5->6

暴力循环

每次找到当前列中最小值,加入到结果链表中,将此值替换为其后继。时间复杂度Nk。 (N为所有链表中的元素个数总和)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public:
    int findMin(vector<ListNode*> &lists) {
        int min = INT_MAX;
        int pos = -1;
        for (int i = 0; i < lists.size(); i++) {
            if (lists[i] && lists[i]->val < min) {
                min = lists[i]->val;
                pos = i;
            }
        }
        return pos;
    }

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        ListNode dummy(0);
        ListNode *curr = &dummy;

        while(true) {
            int pos = findMin(lists);
            if (pos == -1)
                break;
            curr->next = lists[pos];
            curr = lists[pos];
            lists[pos] = lists[pos]->next;
        }

        return dummy.next;
    }
};

改进1: 递归合并

类似 MergeSort,两两递归合并。时间复杂度Nlog(k)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Solution {
public:
    ListNode *mergeTwoLists(ListNode *l1, ListNode *l2) {
        ListNode dummy(0);
        ListNode *curr = &dummy;
        while (l1 && l2) {
            if (l1->val < l2->val) {
                curr->next = l1;
                curr = l1;
                l1 = l1->next;
            } else {
                curr->next = l2;
                curr = l2;
                l2 = l2->next;
            }
        }
        if (l1)
            curr->next = l1;
        if (l2)
            curr->next = l2;

        return dummy.next;
    }
    
    ListNode *merge(vector<ListNode*>& lists, int start, int end) {
        if (start > end) return nullptr;
        if (start == end) return lists[start];
        
        int mid = (start + end) / 2;
        ListNode *left = merge(lists, start, mid);
        ListNode *right = merge(lists, mid+1, end);        
        return mergeTwoLists(left, right);
    }

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        return merge(lists, 0, lists.size()-1);
    }
};

改进2:优先级队列

构造一个规模为 k 的优先级队列(最小堆),初始将各链表头元素入队,每次出队一个元 素,并将其后继入队。时间复杂度Nlog(k)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution{
public:
    struct compareFunc {
        bool operator()(ListNode* node1, ListNode* node2) {
            return node1->val > node2->val;
        }
    };

    ListNode* mergeKLists2(vector<ListNode*>& lists) {
        priority_queue<ListNode*, vector<ListNode*>, compareFunc> pq;

        for (ListNode* node : lists) {
            if (node != nullptr)
                pq.push(node);
        }

        ListNode dummy = ListNode(0);
        ListNode *current = &dummy;

        while (!pq.empty()) {
            current->next = pq.top();
            pq.pop();
            current = current->next;
            if (current->next != nullptr)
                pq.push(current->next);
        }

        return dummy.next;
    }
};