1. 程式人生 > 其它 >[連結串列]leetcode23-合併 k 個升序連結串列

[連結串列]leetcode23-合併 k 個升序連結串列

技術標籤:leetcode# leetcode-連結串列連結串列leetcode

[連結串列]–合併 k 個升序連結串列


題目連結

leetcode 23.合併 k 個升序連結串列

題目

給你一個連結串列陣列,每個連結串列都已經按升序排列。

請你將所有連結串列合併到一個升序連結串列中,返回合併後的連結串列。

示例

輸入:lists = [[1,4,5],[1,3,4],[2,6]]
輸出:[1,1,2,3,4,4,5,6]
解釋:連結串列陣列如下:
[
  1->4->5,
  1->3->4,
  2->6
]
將它們合併到一個有序連結串列中得到。
1->1->2->3->4->4->5->6
輸入:lists = []
輸出:[]

輸入:lists = [[]]
輸出:[]

解析

這個困難模式有點溼潤
leetcode 21.合併兩個有序連結串列 + 分治歸併

  1. 將 k 個連結串列兩兩一組合並,第一次完成之後變為(k/2)個連結串列。依次歸併…
  2. 重複上一步直至有序,也就是剩下一個連結串列

程式碼實現

public class Solution23 {
    /**
     * Definition for singly-linked list
     */
    class ListNode {
        int val;
        ListNode next;
public ListNode(int val) { this.val = val; } } /** * 使用分治 + 合併兩個有序連結串列 */ public ListNode mergeKLists(ListNode[] lists) { return merge(lists, 0, lists.length-1); } /** * 歸併 */ public ListNode merge(ListNode[] lists, int start,
int end) { if (start == end) return lists[start]; if (start > end) return null; int mid = (start + end) / 2; return mergeTwoLists(merge(lists, start, mid), merge(lists, mid+1, end)); } /** * 合併兩個有序連結串列 */ public ListNode mergeTwoLists(ListNode l1, ListNode l2) { ListNode newHead = new ListNode(0); ListNode temp = newHead; while (l1 != null && l2 != null) { if (l1.val < l2.val) { temp.next = l1; temp = temp.next; l1 = l1.next; }else { temp.next = l2; temp = temp.next; l2 = l2.next; } } // 有一個連結串列遍歷完 temp.next = l1 != null ? l1 : l2; return newHead.next; } }

發現了另一種比較有意思的:

  1. 定義傀儡頭結點用於連線新的合併連結串列;
  2. 將每個連結串列第一個節點都裝入優先順序佇列(小根堆),每次彈出一個節點之後將該節點所在連結串列的下一個節點(不為 null)放入優先順序佇列;
  3. 直到優先順序佇列為空。

程式碼實現

public class Solution23 {
    /**
     * Definition for singly-linked list
     */
    class ListNode {
        int val;
        ListNode next;
        public ListNode(int val) {
            this.val = val;
        }
    }

    /**
     * 使用優先順序佇列
     */
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists.length == 0) return null;
        ListNode dummyHead = new ListNode(0);
        ListNode temp = dummyHead;
        // 優先順序佇列——小根堆
        PriorityQueue<ListNode> queue = new PriorityQueue<>((o1, o2) -> o1.val-o2.val);
        // 所有連結串列的第一個節點放入進行排序
        for (int i = 0; i < lists.length; i++) {
            if (lists[i] != null) {
                queue.offer(lists[i]);
            }
        }

        while (!queue.isEmpty()) {
            ListNode next = queue.poll();// 確定彈出的節點是哪個連結串列的
            temp.next = next;
            temp = temp.next;
            // 令彈出節點的連結串列的下一個節點進入佇列
            if (next.next != null) {
                queue.offer(next.next);
            }
        }
        return dummyHead.next;
    }
}

-----------------------------------------------------------------------------有始有終分割線----------------------------------------------------------------------------------