题解 | #合并k个已排序的链表#
合并k个已排序的链表
https://www.nowcoder.com/practice/65cfde9e5b9b4cf2b6bafa5f3ef33fa6
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
/**
*基本思路,在合并2个升序链表时,称头节点较小链表为a链表,另一个链表为b,后续链表b将通过双指针并入链表a:
*定义移动指针初始指向链a头,移动指针向前遍历同时与链b头比较大小,保证链表a上被遍历部分链表总小于等于链表b;
*若移动指针遇到更大值,截断后续链表成为新的链b,原链b接入链a末,移动指针重复上述过程继续向前遍历比较;
*当链a被遍历完毕,将剩余链b直接接入链a末端,得到完整结果链a.
*合并k个升序链表时,基于上述思路,堆排辅助:
*先排空,里面有空链表;
*对k个非空链表头指针列表lists进行最小堆排序,取top为链a头,移动指针依旧初始指向链a头;
*剩余k-1链为准链b,取堆顶链表为链b,
*移动指针保持比较遍历,比较对象为最小堆lists的top;
*若移动指针遇到更大值,截断后续链表插入最小堆,原链b接入链a末(从堆中删除),重复比较遍历;
*若链a被遍历完毕,将链b接入链a,堆空就结束,否则移动指针继续上述操作.
*/
#include <vector>
class Solution {
private:
bool is_heap_empty(vector<ListNode*>& lists) {
return lists.size() <= 1;
}
ListNode* heap_pop(vector<ListNode*>& lists) {
if (is_heap_empty(lists))return nullptr;
ListNode* tmp = lists[1];
int n = lists.size() - 2;
int i = 2;
while (i <= n) {
if (i < n && ((((lists[i])->val) > (lists[i + 1])->val)))i++;
if (((lists[n + 1])->val) > ((lists[i])->val)) {
lists[i >> 1] = lists[i];
i <<= 1; //下滤
} else break;
}
lists[i >> 1] = lists[n + 1];
lists.pop_back();
return tmp;
}
void heap_push(vector<ListNode*>& lists, ListNode* ptr) {
int n = lists.size();
int i = n;
lists.emplace_back(nullptr);
while (i > 1 && (((lists[i >> 1])->val) > (ptr->val))) {
lists[i] = lists[i >> 1];
i >>= 1; //上滤
}
lists[i] = ptr;
}
ListNode* heap_top(vector<ListNode*>& lists) {
if (is_heap_empty(lists))return nullptr;
else return lists[1];
}
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
int n = lists.size();
//去除nullptr
{
int i = 0, cnt = 0;
while (i < n - cnt) {
if (lists[i] == nullptr) {
cnt++;
lists[i] = lists.back();
lists.pop_back();
continue;
}
i++;
}
}
//特殊情况
n = lists.size();
if (n == 0)return nullptr;
if (n == 1)return lists[0];
//最小堆调整: i>=1,父节点No.i的,左孩子为No.2i,右孩子为No.2i+1;
ListNode* tmp = nullptr;
lists.emplace(lists.begin(), nullptr); //now size is n+1
for (int i = n >> 1, j = 0; i > 0; i--) {
tmp = lists[i];
j = i << 1;
while (j <= n) {
if (j < n && (((lists[j])->val) > ((lists[j + 1])->val)))j++;
if ((tmp->val) > ((lists[j])->val)) {
lists[j >> 1] = lists[j];
j <<= 1;//下滤
} else break;
}
lists[j >> 1] = tmp;
}
lists[0] = lists[1]; //哨兵位
//遍历合并各链表
ListNode* dPtr = heap_pop(
lists); //移动指针,初始化为最小端链头,同时pop
ListNode* sPtr = heap_top(lists); //固定指针
while (true) {
while (dPtr->next != nullptr && ((dPtr->next->val) <= (sPtr->val)))
dPtr = dPtr->next;
//dPtr->next == nullptr || dPtr->next->val > sPtr->val
if (dPtr->next == nullptr) {
dPtr->next = heap_pop(lists);
sPtr = heap_top(lists);
if (sPtr == nullptr)break;
else continue;
}
tmp = heap_pop(lists);
heap_push(lists, dPtr->next);
dPtr->next = tmp;
sPtr = heap_top(lists);
}
return lists[0];
}
};
