2020年9月4日 周五 天气晴 【不悲叹过去,不荒废现在,不惧怕未来】
本文目录
1. 优先队列2. 分治合并2.1 递归法2.2 迭代法
这道题有点类似归并排序。
1. 优先队列
class Solution {
public:
struct cmp
{
bool operator()(ListNode
*a
,ListNode
*b
){
return a
->val
> b
->val
;
}
};
ListNode
* mergeKLists(vector
<ListNode
*>& lists
) {
priority_queue
<ListNode
*, vector
<ListNode
*>, cmp
> pq
;
for(auto h
:lists
){
if(h
!=NULL)
pq
.push(h
);
}
ListNode
* preHead
= new ListNode(-1);
ListNode
* cur
= preHead
;
while(!pq
.empty()){
cur
->next
= pq
.top();
pq
.pop();
cur
= cur
->next
;
if(cur
->next
) pq
.push(cur
->next
);
}
return preHead
->next
;
}
};
时间复杂度:考虑优先队列中的元素不超过
k
k
k 个,那么插入和删除的时间代价为
O
(
l
o
g
k
)
O\left( {logk} \right)
O(logk),这里最多有
n
n
n 个点,对于每个点都被插入删除各一次,故总的时间代价即渐进时间复杂度为
O
(
n
l
o
g
k
)
O\left( {nlogk} \right)
O(nlogk)。空间复杂度:这里用了优先队列,优先队列中的元素不超过
k
k
k 个,故渐进空间复杂度为
O
(
k
)
O\left( {k} \right)
O(k)。
2. 分治合并
分治合并也就是两两进行合并。
2.1 递归法
class Solution {
public:
ListNode
* mergeKLists(vector
<ListNode
*>& lists
) {
return merge(lists
,0,lists
.size()-1);
}
ListNode
* merge(vector
<ListNode
*>& lists
, int left
, int right
){
if(left
< right
){
int mid
= left
+ (right
- left
) / 2;
ListNode
* l_list
= merge(lists
,left
,mid
);
ListNode
* r_list
= merge(lists
,mid
+1,right
);
return mergeTwoLists(l_list
,r_list
);
}
else if(left
> right
) return nullptr;
else return lists
[left
];
}
ListNode
* mergeTwoLists(ListNode
* l1
, ListNode
* l2
){
ListNode
* dummyHead
= new ListNode(-1), *tail
= dummyHead
;
while(l1
&& l2
){
if(l1
->val
< l2
->val
){
tail
->next
= l1
;
l1
= l1
->next
;
}
else{
tail
->next
= l2
;
l2
= l2
->next
;
}
tail
= tail
->next
;
}
tail
->next
= l1
?l1
:l2
;
return dummyHead
->next
;
}
};
2.2 迭代法
迭代法合并的过程类似于归并排序。
class Solution {
public:
ListNode
* mergeKLists(vector
<ListNode
*>& lists
) {
int len
= lists
.size();
if(len
== 0) return nullptr;
for(int seg
= 1; seg
< len
; seg
*= 2){
for(int beg
= 0; beg
< len
; beg
+= seg
*2){
int l
= beg
, r
= l
+ seg
;
if(r
< len
) lists
[l
] = mergeTwoLists(lists
[l
],lists
[r
]);
}
}
return lists
[0];
}
ListNode
* mergeTwoLists(ListNode
* l1
, ListNode
* l2
){
ListNode
* dummyHead
= new ListNode(-1), *tail
= dummyHead
;
while(l1
&& l2
){
if(l1
->val
< l2
->val
){
tail
->next
= l1
;
l1
= l1
->next
;
}
else{
tail
->next
= l2
;
l2
= l2
->next
;
}
tail
= tail
->next
;
}
tail
->next
= l1
?l1
:l2
;
return dummyHead
->next
;
}
};
时间复杂度:
O
(
n
l
o
g
k
)
O\left( {nlogk} \right)
O(nlogk)。假设共有
n
n
n 个结点,每次合并都要遍历所有结点。一共有
k
k
k 个链表,最后合并成一个,要遍历
l
o
g
k
logk
logk 次。所以最终的时间复杂度为
O
(
n
l
o
g
k
)
O\left( {nlogk} \right)
O(nlogk)。空间复杂度:递归:
O
(
l
o
g
k
)
O\left( {logk} \right)
O(logk),迭代:
O
(
1
)
O\left( {1} \right)
O(1)。