Merge k Sorted Lists
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Tag: divide and conquer, linked list, heap
update 9/22/2015
Merge sort the k lists. O(knlogk) in time, O(1)
//merge these /** * 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 _mergeKLists(lists, 0, lists.size()); } //not include end, include start ListNode * _mergeKLists(vector<ListNode*>& lists, int start, int end){ //base case if(end - start == 1){ return lists[start]; } int mid = start + (end - start) / 2; ListNode * l1 = _mergeKLists(lists, start, mid); ListNode * l2 = _mergeKLists(lists, mid, end); ListNode dummyNode = ListNode(0); ListNode *tail = &dummyNode; while(l1 != NULL && l2 != NULL){ ListNode*& p = l1->val < l2->val ? l1: l2; tail->next = p; tail = tail->next; p = p->next; } tail->next = l1 == NULL? l2: l1; return dummyNode.next; } };
遇到的第一个hard题,果然够味道。
版本一,用暴力搜,每次从k个lists中找到最小值,链到result里,再更新最小值所在的list。
空间复杂度O(1),时间复杂度大约为O(k*k*n)。k为lists数,n为每个list里平均元素数。
解决了输入为空的问题,版本一遇到了超时。(Time Limit Exceeded)
挂在了k很大的一个测试上。
[{7},{49},{73},{58},{30},{72},{44},{78},{23},{9},{40},{65},{92},{42},{87},{3….大约有几千个。
/** * 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) { ListNode * head = NULL; ListNode * tail = NULL; ListNode * p = NULL; vector<ListNode *>::iterator it,idx; //lists is empty if (lists.empty()){ return NULL; } //some listnode are empty if (lists.size() > 0){ for(it = lists.begin(); it != lists.end(); it++){ if (*it == NULL){ lists.erase(it); it--; // this is important, since iterator should be decreased after erase operation } } } while(lists.size() > 0){ int min = lists[0]->val; idx = lists.begin(); for(it = lists.begin() + 1; it != lists.end(); it++){ if ((*it)->val < min){ min = (*it)->val; idx = it; } } if (head == NULL){ head = tail = *idx; } else{ tail->next = *idx; tail = *idx; } if ((*idx)->next == NULL){ lists.erase(idx); } else{ *idx = (*idx)->next; } } return head; } };
1.20更新:
看了tag,发现要用堆来做。今天复习了分析算法时间复杂度和堆的知识,自己实现了一个堆算法。又学了stl中堆的用法(priority queue)。解决了这道题目。
其中要注意,利用priority_queue时,要查它的函数说明http://en.cppreference.com/w/cpp/container/priority_queue
自己写一个compare类,重载'()’操作符,完成自己的比较需求。
版本二:
利用堆排序,每次取出堆顶元素后,向后移动元素所在listnode的指针,如果为空的话则舍弃,如果不空的话重新插入堆中。不断维护该堆。
记n为每个list中的平均元素个数,k为list数
时间复杂度为O(k*n*logk),空间复杂度为O(k)
C++代码:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class cmp { public: bool operator()(const ListNode * p1, const ListNode * p2) const{ if (p1->val <= p2->val){ return false; } else{ return true; } } }; class Solution { public: ListNode *mergeKLists(vector<ListNode *> &lists) { vector<ListNode *>::iterator it; ListNode * head = NULL; ListNode * tail = NULL; ListNode * p = NULL; //lists is empty if (lists.empty()){ return NULL; } //some elements in lists are empty for(it = lists.begin(); it != lists.end(); it++){ if (*it == NULL){ lists.erase(it); it--; } } if(lists.empty()){ return NULL; } priority_queue<ListNode *, vector<ListNode *>, cmp>pq(cmp(), lists); //handle the first element p = pq.top(); pq.pop(); head = tail = p; p = p->next; if (p != NULL){ pq.push(p); } //loop all the elements while(!pq.empty()){ p = pq.top(); pq.pop(); tail->next = p; tail = tail->next; p = p->next; if(p != NULL){ pq.push(p); } } tail->next = NULL; return head; } };
待完善:
用分治算法。