Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
题目分析:
k个排过序的链表,要将它们合并起来就要求能够在较短的时间内将当前的k个数进行排序,并且能够高效得支持数字的增删操作。
可以使用的方法有:败者树,堆排序,这两个算法在插入、删除节点的时候复杂度都为O(n)。
处理流程:
1. 使用每个链表起始的节点,共k个节点,进行堆排序,复杂度
O(klogk)
2. 之后从这k个节点中选择一个最大的,插入到新的链表中去。
3. 被选中的那个链表的节点的下一个节点如果存在,插入到堆中去。
4. 回到步骤2
结束条件为堆中元素少于等于1个,即只有最后一个链表或没有链表剩余。
使用堆的代码:
需要注意的是,priority_queue默认实现的是最大堆,而stl中的比较函数默认是通过“
<
<script type="math/tex" id="MathJax-Element-132"><</script>”符号来实现,因此实现最小堆的时候要重写比较函数,将<重写为>。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
struct cmp {
bool operator()(ListNode *n1, ListNode *n2) {
return n1->val > n2->val;
}
};
class Solution {
public:
ListNode *mergeKLists(vector<ListNode *> &lists) {
priority_queue<ListNode *, vector<ListNode *>, cmp> min_heap;
for(int i = 0; i < lists.size(); ++i) {
if(lists[i] != NULL)
min_heap.push(lists[i]);
}
ListNode *pre_head(new ListNode(0)), *curr(pre_head);
while(min_heap.size() > 1) {
curr->next = min_heap.top();
min_heap.pop();
curr = curr->next;
if(curr->next != NULL)
min_heap.push(curr->next);
}
if(min_heap.size() == 1) {
curr->next = min_heap.top();
min_heap.pop();
}
ListNode *head = pre_head->next;
pre_head->next = NULL;
delete pre_head;
return head;
}
};
使用败者树的代码:
/**
* 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) {
int size = lists.size();
if (size == 0)
return NULL;
int *key = new int[size + 1];
key[size] = INT_MIN;
ListNode **elements = new ListNode*[size];
int *loser = new int[size];
for (int i = 0; i < size; i++) {
elements[i] = lists[i];
loser[i] = size;
if (elements[i] != NULL)
key[i] = elements[i]->val;
else key[i] = INT_MAX;
}
for (int i = 0; i < size; i++) {
adjust(loser, key, i, size);
}
ListNode *head = NULL, *curr = NULL;
while (true) {
if (key[loser[0]] == INT_MAX) {
break;
curr->next = NULL;
}
if (head == NULL) {
head = elements[loser[0]];
curr = elements[loser[0]];
elements[loser[0]] = elements[loser[0]]->next;
}
else {
curr->next = elements[loser[0]];
curr = curr->next;
elements[loser[0]] = elements[loser[0]]->next;
}
if(elements[loser[0]] != NULL)
key[loser[0]] = elements[loser[0]]->val;
else
key[loser[0]] = INT_MAX;
adjust(loser, key, loser[0], size);
}
return head;
}
void adjust(int loser[], int key[], int k, int size) {
for (int i = (size + k)/2; i > 0; i /= 2) {
if (key[loser[i]] < key[k]) {
int temp = k;
k = loser[i];
loser[i] = temp;
}
}
loser[0] = k;
}
};