[LeetCode hot 100] 23. 合并k个升序链表
题目链接
如果是合并两个链表那没得说,两个指针分别指向两个链表,每次把小的那个后移。
但是这里是k个,如果用k个指针,每次移动最小的,那么每次都需要遍历一遍找到最小的那个,时间复杂度太高了。
从k个里面找最小,这个情景很适合使用【堆】这种结构。关于堆的知识点传送门
这里使用小根堆,因为每次要获得最小的,那么小根堆取堆顶就能很轻松地完成这个工作。堆顶是一个指针,指向某个链表的遍历位置,当取了堆顶之后,需要将遍历指针向后移动一位,并且重新加入到堆中,这里就是把堆顶替换掉,然后向下调整,最为方便。
下面是完整代码,其中我偷了点懒,建堆就直接用排序代替了。
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 53 54 55 56 57 58
|
class Solution { public: void adjustDown(vector<ListNode*>& heap){ int parent = 0; while(2 * parent + 1 < heap.size()){ int lchild = 2 * parent + 1; int minChild = lchild; if(lchild + 1 < heap.size()){ int rchild = lchild + 1; minChild = heap[lchild]->val < heap[rchild]->val ? lchild : rchild; } if(heap[parent]->val < heap[minChild]->val){ return; } swap(heap[parent], heap[minChild]); parent = minChild; } return; } void headPop(vector<ListNode*>& heap){ swap(heap[0], heap[heap.size() - 1]); heap.pop_back(); adjustDown(heap); }
ListNode* mergeKLists(vector<ListNode*>& lists) { vector<ListNode*> heap; for(auto& head : lists){ if(head) heap.push_back(head); } sort(heap.begin(), heap.end(), [](ListNode* a, ListNode* b){return a->val < b->val;}); ListNode dummy(0); ListNode* cur = &dummy; while(heap.size() > 0){ cur->next = new ListNode(heap[0]->val); cur = cur->next; if(heap[0]->next == nullptr){ headPop(heap); } else { heap[0] = heap[0]->next; adjustDown(heap); } cout<<heap.size()<<endl; } return dummy.next; } };
|
自己独立写出来了,有点子感动。