題目敘述
- 題目難度:
Easy
- 題目描述: 給定兩個已排序 linked list 的
head
,希望能夠合併成一個已排序的list
解法
一開始的想法
一開始我想說可以先走訪 list1
然後逐項比對 list2
的item,如果 list1
中的元素小於 list2
的,就插入到 list2
,並且插入後,再繼續迭代 list1
當中的元素
原始代碼:
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 39 40 41 42 43 44
| Node *ptr1, *ptr2, *previous, *preceding; ptr1 = list1; ptr2 = list2; preceding = ptr1; previous = ptr2;
if(ptr1==NULL && ptr2==NULL){ return ptr1; } else if (ptr1 == NULL ){ return ptr2; } else if (ptr2 == NULL){ return ptr1; }
while (ptr1 != NULL){ while (ptr2 !=NULL){ if (ptr1-> val <= ptr2->val){ preceding = ptr1->next; ptr1->next = ptr2; previous->next = ptr1; previous = previous -> next; break; } else{ previous = ptr2; ptr2 = ptr2->next; }
} ptr1 = preceding; } return list2;
|
但這種做法會在 previous
, preceding
更新指標時候會出問題,並且還需要額外判斷 Tail node,由於太過麻煩後續我就放棄這種做法
我的解法
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 39 40
|
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
struct ListNode *ptr1, *ptr2; struct ListNode dummy; struct ListNode *tail = &dummy; ptr1 = list1; ptr2 = list2; tail->next = NULL;
while (ptr1 != NULL && ptr2 != NULL){ if (ptr1->val <= ptr2->val){ tail->next = ptr1; ptr1 = ptr1->next;
} else{ tail->next = ptr2; ptr2 = ptr2->next; } tail = tail -> next;
} if (ptr1 != NULL) { tail->next = ptr1; } if (ptr2 != NULL) { tail->next = ptr2; }
return dummy.next; }
|
說明
我後面取而代之的是,建立新的 Linked List 在比較兩個lists的時候就放到新創建的list中
- 先建立一個Linked List,將要返回的內容串接在後面
- 比較兩個Linked List 的value大小,將較小的加入dummy list
- 加入後,原先list的元素會少一個,因此會需要將指標更新 (
ptr2 = ptr2->next;
, ptr1 = ptr1->next;
)
- 結束後,若還有剩餘的元素在,就在直接加進 dummy 串列中
- 最後回傳 dummyy串列中第一個有值的位址
參考: https://hackmd.io/@ChangTL/S1z11PWJv#021-Merge-Two-Sorted-Lists
執行結果
其他做法
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| class Solution { public: ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) { if(list1 == NULL) return list2; if(list2 == NULL) return list1; ListNode * ptr = list1; if(list1 -> val > list2 -> val) { ptr = list2; list2 = list2 -> next; } else { list1 = list1 -> next; } ListNode *curr = ptr; while(list1 && list2) { if(list1 -> val < list2 -> val){ curr->next = list1; list1 = list1 -> next; } else{ curr->next = list2; list2 = list2 -> next; } curr = curr -> next; } if(!list1) curr -> next = list2; else curr -> next = list1; return ptr; } };
|
- Time Complexity: $O(n+m)$
- Space Complexity: $O(1)$
執行結果
時間複雜度分析
時間複雜度
在這個合併兩個已排序linked list的函數中,我們主要考慮走訪每個節點所需的時間,在最壞情況下,兩個linked list中的每個節點都需要被traverse一次
- 假設
list1
有n
個節點,而 list2
有 m
個節點
- 因此,整個過程中,走訪的節點總數是
n + m
- 節點的比較和鏈結操作都是常數時間操作
- 所以,時間複雜度是 $O(n + m)$
空間複雜度
空間複雜度分析考慮的是程式執行所需的額外記憶體空間,在這個函數中:
- 使用了一個 dummy 節點,它的空間是常數級別的 $O(1)$
- 其餘使用的指標 (如 ptr1
, ptr2
, tail
) 也都是常數級別的空間
- 所以空間複雜度會是 $O(1)$