Merge k Sorted Lists
Solution 1
对于两个链表合并操作的扩展。一个思路就是比较合并过程中各个链表未合并部分的最小值中的最小值,如果直接K个进行比较时间复杂度并不理想,因此使用优先队列进行维护,这里重新复习了以下自定义优先级函数的写法。
- 时间复杂度: O ( N log K ) O(N \log K) O(NlogK), N N N为所有结点个数总和, K K K为欲合并链表的个数,优先队列将每一步选择最小值的操作简化到了对数时间
- 空间复杂度: O ( N + K ) O(N + K) O(N+K) , N N N为所有结点个数总和, K K K为欲合并链表的个数,前者为结果的保存占用,后者为队列的占用
/**
* Definition for singly-linked list.
* 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) {}
* };
*/
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> checkQueue;
for (auto head: lists) {
if (head != nullptr) {
checkQueue.push(head);
}
}
ListNode* head = new ListNode();
ListNode* ans = head;
while (!checkQueue.empty()) {
auto check = checkQueue.top();
checkQueue.pop();
head->next = check;
head = head->next;
check = check->next;
if (check != nullptr) {
checkQueue.push(check);
}
}
return ans->next;
}
};
Solution 2
另外一个思路就是基于每一个下列表既定顺序了之后,直接使用归并排序实现。
- 时间复杂度: O ( N log K ) O(N \log K) O(NlogK), N N N为所有结点个数总和, K K K为欲合并链表的个数
- 空间复杂度: O ( 1 ) O(1) O(1),没有额外占用,只有状态变量维护
/**
* Definition for singly-linked list.
* 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) {}
* };
*/
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
int K = lists.size();
if (K == 0) {
return nullptr;
}
int internal = 1;
while (internal < K) {
for (int i = 0; i < K - internal; i += internal * 2) {
lists[i] = this->merge2Lists(lists[i], lists[i + internal]);
}
internal *= 2;
}
return lists[0];
}
private:
ListNode* merge2Lists(ListNode* a, ListNode* b) {
ListNode* head = new ListNode();
ListNode* ans = head;
while (a != nullptr && b != nullptr) {
if (a->val < b->val) {
head->next = a;
head = head->next;
a = a->next;
}
else {
head->next = b;
head = head->next;
b = b->next;
}
}
if (a != nullptr) { head->next = a; }
if (b != nullptr) { head->next = b; }
return ans->next;
}
};
Solution 3
Solution 1的Python实现,使用了Python内建的heapq实现,注意为了确保两个Node的val相同的时候也能正常比较(没有办法直接改node大小定义),加入一个id函数结果在实例元素前。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
import heapq
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
checkQueue = list()
head = ListNode()
ans = head
print(len(lists))
for headNode in lists:
if headNode is not None:
# print(headList)
# print(headList.val)
heapq.heappush(checkQueue, (headNode.val, id(headNode), headNode))
while len(checkQueue) > 0:
_, _, node = heapq.heappop(checkQueue)
head.next = node
head = head.next
node = node.next
if node is not None: heapq.heappush(checkQueue, (node.val, id(node), node))
return ans.next
Solution 4
Solution 2的Python实现。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
import heapq
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
K = len(lists)
if K == 0:
return None
internal = 1
while internal < K:
for i in range(0, K - internal, internal * 2):
lists[i] = self._merge2Lists(lists[i], lists[i + internal])
internal *= 2
return lists[0]
def _merge2Lists(self, a: ListNode, b:ListNode) -> ListNode:
head = ListNode()
ans = head
while a is not None and b is not None:
if a.val < b.val:
head.next = a
head = head.next
a = a.next
else:
head.next = b
head = head.next
b = b.next
if a is not None: head.next = a
if b is not None: head.next = b
return ans.next