Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
<Solution>
這題是 Merge Two Sorted List 的延伸
現在有 k 個 list,最直接想法就是先 merge 兩個,然後再和之後每一個 merge
meage list_1 和 list_2,拿到 list_a
meage list_a 和 list_3,拿到 list_b
meage list_b 和 list_4,拿到 list_c
list_c 就是答案
但這樣不夠有效率
這題是要 merge 好 k 個 sorted list,其實就是在做 merge sort 一樣
要用 divide and conquer 的方式來處理
有 list_1,list_2,list_3,list_4
list_1 和 list_2 merge 得到 list_a,list_3 和 list_4 merge 得到 list_b
最後再 merge list_a 和 list_b 就可以得到答案
code 如下
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Definition for singly-linked list. | |
* struct ListNode { | |
* int val; | |
* ListNode *next; | |
* ListNode(int x) : val(x), next(NULL) {} | |
* }; | |
*/ | |
class Solution { | |
public: | |
ListNode* mergeKLists(vector<ListNode*>& lists) { | |
if(lists.size() == 0) { | |
return NULL; | |
} | |
return divideAndConquer(0, lists.size()-1, lists); | |
} | |
//> merge two sorted list | |
ListNode *mergeList(ListNode *list_1, ListNode *list_2) { | |
ListNode *tmpHead = new ListNode(0); | |
ListNode *tmpCurr = tmpHead; | |
while(list_1 && list_2) { | |
if(list_1->val < list_2->val) { | |
tmpCurr->next = list_1; | |
tmpCurr = list_1; | |
list_1 = list_1->next; | |
} | |
else { | |
tmpCurr->next = list_2; | |
tmpCurr = list_2; | |
list_2 = list_2->next; | |
} | |
} | |
if(list_1) { | |
tmpCurr->next = list_1; | |
} | |
if(list_2) { | |
tmpCurr->next = list_2; | |
} | |
return tmpHead->next; | |
} | |
//> divide lists into left part and right part | |
ListNode *divideAndConquer(const int &left, const int &right, vector<ListNode*>& lists) { | |
if(left == right) { | |
return lists[left]; | |
} | |
else if(left == (right - 1)) { | |
return mergeList(lists[left], lists[right]); | |
} | |
int mid = (left + right) / 2; | |
ListNode *myList_1 = divideAndConquer(left, mid, lists); | |
ListNode *myList_2 = divideAndConquer(mid+1, right, lists); | |
return mergeList(myList_1, myList_2); | |
} | |
}; |
可以使用 std::priority_queue,預設是 max heap
但只要改變用來比較的函數,就可以變成 min heap
使用 min heap 的想法如下
- 先把每個 list 的最小元素丟到 min heap
- 只要 min heap 不為空,持續以下動作
- 拿出第一個元素,串到答案的 link list。因為 min heap 的特性,每次拿到的一定是當前最小的元素
- 檢查當前的元素是否是最後一個元素,不是的話,再丟進去 min heap
c++
Kotlin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Definition for singly-linked list. | |
* struct ListNode { | |
* int val; | |
* ListNode *next; | |
* ListNode(int x) : val(x), next(NULL) {} | |
* }; | |
*/ | |
class Solution { | |
public: | |
//> make priority_queue become min heap | |
struct myCmp { | |
bool operator() (ListNode *a, ListNode *b) { | |
return a->val > b->val; | |
} | |
}; | |
ListNode* mergeKLists(vector<ListNode*>& lists) { | |
priority_queue<ListNode*, vector<ListNode*>, myCmp> minHeap; | |
//> put smallest element of each list into minHeap | |
for(int i = 0; i < lists.size(); i++) { | |
if(lists[i]) { | |
minHeap.push(lists[i]); | |
} | |
} | |
ListNode *head = new ListNode(0); | |
ListNode *curr = head; | |
//> merge remaining elements | |
while(!minHeap.empty()) { | |
ListNode *tmp = minHeap.top(); | |
minHeap.pop(); | |
curr->next = tmp; | |
curr = curr->next; | |
if(tmp->next) { | |
minHeap.push(tmp->next); | |
} | |
} | |
return head->next; | |
} | |
}; |
Kotlin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Example: | |
* var li = ListNode(5) | |
* var v = li.`val` | |
* Definition for singly-linked list. | |
* class ListNode(var `val`: Int) { | |
* var next: ListNode? = null | |
* } | |
*/ | |
class Solution { | |
fun mergeKLists(lists: Array<ListNode?>): ListNode? { | |
val pq = PriorityQueue { v1: Int, v2: Int -> v1 - v2 } | |
var pointer: ListNode? | |
for (list in lists) { | |
pointer = list | |
while(pointer != null) { | |
pq.add(pointer!!.`val`) | |
pointer = pointer.next | |
} | |
} | |
val dummyHead = ListNode(-1) | |
var curr = dummyHead | |
while(pq.isNotEmpty()) { | |
curr.next = ListNode(pq.first()) | |
curr = curr.next | |
pq.remove() | |
} | |
return dummyHead.next | |
} | |
} |
沒有留言:
張貼留言