题解 | #合并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];
    }
};

全部评论

相关推荐

点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务