題記
轉眼已過去很多年了,登錄園子看到幾年前自己記錄的筆記,感慨萬千,慶幸的是自己還在這行沒有放棄,不過,隨着工作經驗的積累,感覺自己越來越無知,索性最近又撿起9年前剛畢業工作那會兒無知的勁兒,來刷題換換腦子~~~
題目描述
該題來自LeetCode第21題:合並兩個有序鏈表
https://leetcode-cn.com/problems/merge-two-sorted-lists/
將兩個升序鏈表合並為一個新的 升序 鏈表並返回。新鏈表是通過拼接給定的兩個鏈表的所有節點組成的。
示例:
輸入:l1 = [1,2,4], l2 = [1,3,4]
輸出:[1,1,2,3,4,4]
解題思路
- 創建一個虛擬頭節點,其下一個節點為從L1, L2的頭節點中選取值較小的節點,假設合並完成,則返回輔助節點的下一個節點,即為最終鏈表的頭節點;
- 新建一個輔助節點,比較L1, L2當前節點的值,其下一個節點也指向L1, L2中值較小的節點,向后移動較小值的節點,同時輔助節點也后移一位;
- 重復第2步,直至L1, L2其中一個鏈表遍歷完成, 輔助節點的下一個節點指向剩下未遍歷完成的鏈表即可。
總結下來,其實就像是拿着一個針(輔助節點)穿珠子,比較兩串珠子頭上一顆珠子的大小,把小的穿上(輔助節點的下一個節點指向二者小的節點),重復該動作,到其中一串珠子穿完,剩下的無需比較直接穿到后面即可。
通過文字描述還是比較抽象,通過畫圖的形式來演示每一步,相對來說,就比較好理解了,我按照上述步驟畫了一下推演圖,如下:
- compare比較鏈表頭節點大小
- pre下一個節點指向值小的鏈表
- 較小的鏈表頭向后移動一位
- pre也向后移動一位(指向合並后的鏈表尾節點)
Java代碼實現
public class MergeTwoLists {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
if (l2 == null) return l1;
// 虛擬頭節點,下一個節點指向L1,L2二者中較小的頭節點
ListNode preHead = new ListNode(-1);
// 輔助節點引用
ListNode pre = preHead;
while (l1 != null && l2 != null) {
// 輔助節點的下一個節點為值小的節點
// 較小值的節點向后移動
if (l1.val > l2.val) {
pre.next = l2;
l2 = l2.next;
} else {
pre.next = l1;
l1 = l1.next;
}
// 輔助節點也同步向后移動
pre = pre.next;
}
// 如果其中一個鏈表已經結束,則剩下節點接到后面即可
pre.next = l1 == null ? l2 : l1;
// 返回虛擬頭節點的下一個節點
return preHead.next;
}
}
總結
該解法的時間復雜度為O(m+n), m、n分別為鏈表L1、L2的長度;空間復雜度為 O(1), 引入了輔助節點,沒有利用其它額外的空間。另外,還有另外一種解法是遞歸,俗話說,遞歸是一看就會,一寫就跪,等有空了再試試。