力扣23. 合并K个排序链表(分治)
https://leetcode-cn.com/problems/merge-k-sorted-lists/
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
一、优先法
维护当前每个链表没有被合并的元素的最前面一个,k 个链表就最多有 k 个满足这样条件的元素,每次在这些元素里面选取 val
属性最小的元素合并到答案中。
时间复杂度为 O(k*n*logk)
空间复杂度为 O(1)
ListNode* mergeKLists(vector<ListNode*>& lists)
{
ListNode* head = new ListNode(0);
ListNode* cur = head;
int nsize = 0;
//找出非空的链
for (int i = 0; i < lists.size(); i++)
{
if (lists[i] == nullptr)
{
nsize++;
}
}
int size = lists.size();
while (nsize < size)
{
//找链的最少值就是链的第一个值的比较
int temp = 2147483647;
int num = -1;//记住第几位
for (int i = 0; i < lists.size(); i++)
{
if (lists[i] != nullptr && lists[i]->val <= temp)
{
num = i;
temp = lists[i]->val;
}
}
//找到最小值的行才去合并
if (num != -1)
{
//合并链表
cur->next = &lists[num][0];
cur = cur->next;
cout << cur->val << '\t';
lists[num] = lists[num]->next;
//链没有了,空指针,说明完成一条链的合并了
if (lists[num] == nullptr)nsize++;
}
}
return head->next;
}
二、分治合并
从归并排序中启发可以用分治合并
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);
}
三、汇总
#include "stdafx.h"
#include <vector>
#include <iostream>
using namespace std;
struct ListNode
{
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
class Solution
{
public:
ListNode* mergeKLists(vector<ListNode*>& lists)
{
ListNode* head = new ListNode(0);
ListNode* cur = head;
int nsize = 0;
//找出非空的链
for (int i = 0; i < lists.size(); i++)
{
if (lists[i] == nullptr)
{
nsize++;
}
}
int size = lists.size();
while (nsize < size)
{
//找链的最少值就是链的第一个值的比较
int temp = 2147483647;
int num = -1;//记住第几位
for (int i = 0; i < lists.size(); i++)
{
if (lists[i] != nullptr && lists[i]->val <= temp)
{
num = i;
temp = lists[i]->val;
}
}
//找到最小值的行才去合并
if (num != -1)
{
//合并链表
cur->next = &lists[num][0];
cur = cur->next;
cout << cur->val << '\t';
lists[num] = lists[num]->next;
//链没有了,空指针,说明完成一条链的合并了
if (lists[num] == nullptr)nsize++;
}
}
return head->next;
}
};
int main()
{
ListNode head1[3] = { 1,4,5 };
head1[0].next = &head1[1]; head1[1].next = &head1[2];
ListNode head2[3] = { 1,3,4 };
head2[0].next = &head2[1]; head2[1].next = &head2[2];
ListNode head3[2] = { 2,6 };
head3[0].next = &head3[1];
vector<ListNode*> lists;
lists.push_back(head1); lists.push_back(head2); lists.push_back(head3);
Solution s;
auto result = s.mergeKLists(lists);
return 0;
}