---
title: 【LeetCode】0023. Merge k Sorted Lists
date: 2023-02-15
is_modified: false
disqus: cynthiahackmd
categories:
- "面試刷題"
tags:
- "LeetCode"
---
{%hackmd @CynthiaChuang/Github-Page-Theme %}
<br>
You are given an array of `k` linked-lists `lists`, each linked-list is sorted in ascending order.
Merge all the linked-lists into one sorted linked-list and return it.
<!--more-->
<br>
**Example 1:**
```
nput: lists = [[1,4,5],[1,3,4],[2,6]]
Output: [1,1,2,3,4,4,5,6]
Explanation: The linked-lists are:
[
1->4->5,
1->3->4,
2->6
]
merging them into one sorted list:
1->1->2->3->4->4->5->6
```
<br>
**Example 2:**
```
Input: lists = []
Output: []
```
<br>
**Constraints**:
- k == lists.length
- 0 <= k <= 104
- 0 <= lists[i].length <= 500
- -104 <= lists[i][j] <= 104
- lists[i] is sorted in ascending order.
- The sum of lists[i].length will not exceed 104.
<br>
**Related Topics:** `Linked List` `Divide and Conquer` `Heap (Priority Queue)` `Merge Sort`
## 解題邏輯與實作
之前有解過寫過一篇 [0021. Merge Two Sorted Lists](https://hackmd.io/@CynthiaChuang/LeetCode-0021-Merge-Two-Sorted-Lists),這題就是它的進階。
我打算按照提示中的分而治之(Divide and Conquer)法與遞迴不斷將鏈結串列剖半對分,直到剩下一個或是兩個鏈結串列時,開始合併與回傳。
以長度為 6 的鏈結串列 [A, B, C, D, E, F] 為例,用遞迴去剖半對分的話最終會是 A、B 排,AB 排後再跟 C 排,再 D、E 排,DE 排後再跟 F 排,最後 ABC 與 DEF 再排一次,總共執行了 5 次。
```python=
class Solution:
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
return self.merged(lists, 0, len(lists))
def merged(self, lists: List[Optional[ListNode]], start_idx: int, end_idx: int) -> Optional[ListNode]:
len_list = end_idx-start_idx;
if len_list <= 0:
return None
merged_result = lists[start_idx]
if len_list > 1:
k = round(len_list/ 2);
merged_result = self.mergeTwoLists(self.merged(lists, start_idx, start_idx+k),
self.merged(lists, start_idx+k, end_idx))
return merged_result
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
answer = ListNode(-1)
head = answer
while list1 and list2:
if list1.val < list2.val:
answer.next = list1
list1 = list1.next
else:
answer.next = list2
list2 = list2.next
answer = answer.next
answer.next = list1 if list1 else list2
return head.next
```
Runtime 為 112 ms,Beats 是 78.87%。不過它效率比我想像中的還差。
<br class="big">
因此我打算換個寫法試試,一樣是分而治之法,不過把它改成直接兩兩抓來做排序,就是 A、B 排、C、D 排、C、D 排:
```python=
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
len_list = len(lists)
print("vvvv", len_list)
if len_list == 0:
return None
resules = lists
while len_list > 1:
if len_list % 2 != 0:
resules.append(None)
len_list += 1
new_resule = []
for i in range(0, len_list, 2):
new_resule.append(self.mergeTwoLists(resules[i], resules[i+1]))
resules = new_resule
len_list = len(resules)
return resules[0]
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
answer = ListNode(-1)
head = answer
while list1 and list2:
if list1.val < list2.val:
answer.next = list1
list1 = list1.next
else:
answer.next = list2
list2 = list2.next
answer = answer.next
answer.next = list1 if list1 else list2
return head.next
```
效果出來出乎意料的不錯欸,Runtime 96 ms、Beats 95.64%。
<br class="big">
偷看了下 70ms 的答案,因為它直接用 sort 難怪效能不錯 XDDD
```python=
class Solution:
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
head = temp = ListNode()
arr = []
for l in lists:
while l != None:
arr.append(l.val)
l = l.next
arr.sort()
for a in arr:
temp.next = ListNode()
temp = temp.next
temp.val = a
return head.next
```
## 其他連結
1. [【LeetCode】0000. 解題目錄](/@CynthiaChuang/LeetCode-0000-Contents)
## 更新紀錄
:::spoiler 最後更新日期:2023-02-15
- 2023-02-15 發布
- 2023-01-11 完稿
- 2023-01-11 起稿
:::
{%hackmd @CynthiaChuang/Github-Page-Footer %}