天天看點

leetcode-23. 合并K個升序連結清單

leetcode-23. 合并K個升序連結清單
leetcode-23. 合并K個升序連結清單

JAVA解法

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        // 定義一個維護最終答案的 ans 連結清單
        ListNode ans = null;
        // 周遊 lists 中的所有連結清單
        for (int i = 0; i < lists.length; ++i) {
            // 其中兩兩合并
            ans = mergeTwoLists(ans, lists[i]);
        }
        // 傳回最終合并完的答案
        return ans;
    }
    // 實作兩兩合并的邏輯
    public ListNode mergeTwoLists(ListNode a, ListNode b) {
        // 隻要有一個連結清單為空則傳回另一個
        if (a == null || b == null) {
            return a != null ? a : b;
        }
        // 定義一個值為 0 的頭節點
        ListNode head = new ListNode(0);
        // 定義 tail 結點并讓頭節點指向它,定義兩個分别指向傳進的兩連結清單的指針節點
        ListNode tail = head, aPtr = a, bPtr = b;
        // 隻有連個指針節點不為空的時候進行周遊
        while (aPtr != null && bPtr != null) {
            // 兩兩值的比較并把 tail.next 指向較小的那個
            if (aPtr.val < bPtr.val) {
                tail.next = aPtr;
                // 因為此時較小的已經存進去了,維護指針位置為原 aPtr 的下一個
                aPtr = aPtr.next;
            } else {
                tail.next = bPtr;
                // 因為此時較小的已經存進去了,維護指針位置為原 bPtr 的下一個
                bPtr = bPtr.next;
            }
            // 因為 tail 已經更新是以要維護 tail 的位置為原 tail 的下一個
            tail = tail.next;
        }
        // 若 aPtr == null 則證明 aPtr 到盡頭了,則接上 bPtr 即可,反之同理
        tail.next = (aPtr != null ? aPtr : bPtr);
        // 最後傳回
        return head.next;
    }
}           

複制

題解分析

這道題合并多個有序連結清單,結合之前做過的合并兩個有序連結清單,這道題可以被拆成一個主線:周遊所有存在的連結清單,一個支路:用雙指針合并合并兩個有序連結清單。

首先,在主線中定義一個維護最終答案的 ans 連結清單,然後周遊 lists 中的所有連結清單,其中進入支路讓連結清單兩兩合并,合并完則傳回。

支路邏輯:傳進來的兩個連結清單隻要有一個連結清單為空則傳回另一個。定義一個虛拟的頭節點值為 0,定義 tail 結點并讓頭節點指向它,定義兩個分别指向傳進的兩連結清單的指針節點,隻有連個指針節點不為空的時候進行周遊。兩指針節點所在的節點值兩兩值的比較并把 tail.next 指向較小的那個,同時那個較小那個的節點已經被使用,是以要讓其指派為下一個節點,此時分的 taill 同理也要維護。

到此已經完成相同長度的合并了,若 aPtr == null 則證明 aPtr 到盡頭了,則接上 bPtr 即可,反之 aPtr != null 則并上 aPtr,因為上面的循環條件是 aPtr != null && bPtr != null,就是因為有一方為空才結束循環,但仍然還有一個連結清單剩下沒合并的部分,因為是有序的,是以直接合并即可。

做題感想

第一次接觸 hard 題,還是費了不少時間,一道題近一個鐘,還是感覺到了 hard 題的威力了,但是看評論這道題還是 hard 題裡邊算簡單的了,還要再接再厲。

leetcode原題:23. 合并K個升序連結清單