过完国庆节,在假期中没有去写有关leetcode题目,今天会慢慢分析题目,今天是23题,是个困难的的题目,但是我拿到题目就像到了最基本的解法,下面我们来看看吧!
第二十三题:合并K个升序链表
解题思路:拿到这个题目后,我的想法是,合并2个链表的做法,然后在顺序合并,这样时间复杂度就是0(k^2 * N)空间复杂 度可为0(1),第二个想法是比较第一个数据最小,然后使用优先队列优化,然后统一合并。本例子采用了第一个想法。
代码:
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
//方法1 合并法
ListNode * mergeList(ListNode * result, ListNode * curList)
{
if ( (!result) || (!curList))
{
return result ? result : curList;
}
ListNode head, * nowlist = &head, *reslist = result, *cur = curList;
while (reslist && cur)
{
if (reslist->val < cur->val)
{
nowlist->next = reslist; reslist = reslist->next;
}
else
{
nowlist->next = cur; cur = cur->next;
}
nowlist = nowlist->next;
}
nowlist->next = (reslist ? reslist : cur);
return head.next;
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode * result = nullptr;
for (int i = 0; i < lists.size();++i)
{
result = mergeList(result,lists[i]);
}
return result;
}
然后去找了官方对应的解答,使用priority_queue (优先队列)
代码:
// 小根堆的回调函数
struct cmp{
bool operator()(ListNode *a,ListNode *b){
return a->val > b->val;
};
ListNode* mergeKLists(vector<ListNode*>& lists) {
priority_queue<ListNode*, vector<ListNode*>, cmp> pri_queue;
// 建立大小为k的小根堆
for(auto elem : lists){
if(elem) pri_queue.push(elem);
}
// 可以使用哑节点/哨兵节点
ListNode dummy(-1);
ListNode* p = &dummy;
// 开始出队
while(!pri_queue.empty()){
ListNode* top = pri_queue.top(); pri_queue.pop();
p->next = top; p = top;
if(top->next) pri_queue.push(top->next);
}
return dummy.next;
}
时间复杂度:考虑优先队列中的元素不超过 k 个,那么插入和删除的时间代价为 O(logk),这里最多有 kn 个点,对于每个点都被插入删除各一次,故总的时间代价即渐进时间复杂度为 O(kn×logk)。
空间复杂度:这里用了优先队列,优先队列中的元素不超过 k 个,故渐进空间复杂度为 O(k)。
官方同时给出了分治合并:
故渐进时间复杂度为O(kn×logk)。 空间复杂度:递归会使用到 O(logk) 空间代价的栈空间。
代码:
ListNode* mergeTwoLists(ListNode *a, ListNode *b) {
if ((!a) || (!b)) return a ? a : b;
ListNode head, *tail = &head, *aPtr = a, *bPtr = b;
while (aPtr && bPtr) {
if (aPtr->val < bPtr->val) {
tail->next = aPtr; aPtr = aPtr->next;
} else {
tail->next = bPtr; bPtr = bPtr->next;
}
tail = tail->next;
}
tail->next = (aPtr ? aPtr : bPtr);
return head.next;
}
ListNode* merge(vector <ListNode*> &lists, int l, int r) {
if (l == r) return lists[l];
if (l > r) return nullptr;
int mid = (l + r) >> 1;
return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
}
ListNode* mergeKLists(vector<ListNode*>& lists) {
return merge(lists, 0, lists.size() - 1);
}
已上就是这个题目的解法了。有关优先队列可以查看相应的数据结构,与stl。