23. 合并K个升序链表

23. 合并K个升序链表_第1张图片
23. 合并K个升序链表_第2张图片
1.暴力法:遍历每一条链表,将每个结点加入vector,然后对vector进行sort,cmp的用法是如果返回值为1就不交换。最后遍历链表,创建新链表即可,重点是将最后tmp的next设为空指针!!必须必须,链表结尾必须为空
2.分治法:归并排序,写一个切分函数,再写一个merge函数,因为数组中存的是链表的头,而每一条链表又是有序的,所以当我们切分到一个结点时,就当做切分完毕,只剩一条链表就是有序的(和只剩一个元素就算是有序的右异曲同工之妙)。left和right相等时就是切分完毕,返回lists[left]即可,否则就进行切分,mid不多说,两条新链表分别为左合并后的有序链表和右合并后的有序链表。最后返回merge这两条链表的结果。所以l1和l2要不就是切分到一个结点返回的链表,要不就是合并后的链表,当切分到一条链表时就对其和另一个进行合并。
合并操作:如果一条链表为空,就返回另一条。定义一个哨兵结点和一个tmp往前走,接下来就是合并两个有序链表,懂的都懂,最后返回哨兵的next即可

/**
 * 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:
    /*static bool cmp(ListNode* a, ListNode* b){
        return a->val < b->val;//如果a
    ListNode* merge(ListNode* l1, ListNode* l2){
        if(l1 == nullptr || l2==nullptr){
            return l1==nullptr ? l2:l1;
        }
        //如果用l1或者l2中较小的那个点直接赋值给head,而不是新建结点,可以省很多内存,那样的话head就不是哨兵了,就是名副其实的头结点
        ListNode* head = new ListNode(0);
        ListNode* tmp = head;
        while(l1!=nullptr && l2!=nullptr){
            if(l1->val <= l2->val){
                tmp->next = l1;
                l1 = l1->next;
            }
            else{
                tmp->next = l2;
                l2 = l2->next;
            }
            tmp = tmp->next;
        }
        tmp->next = l1==nullptr?l2:l1;
        return head->next;;
    }

    ListNode* qiefen(vector<ListNode*>& lists,int left, int right){
        //当左右相等,证明切分到一个元素了,也就是一条链表
        if(left == right) return lists[left];
        int mid = left + (right-left)/2;
        ListNode* l1 = qiefen(lists,left,mid);
        //切分返回的值是一条归并排序完成的链表或者单独一条链表,也就是left==right的情况,只有一条链表默认是有序的,就和一个元素一定有序一样
        //l1和l2是两条切分好的链表
        ListNode* l2 = qiefen(lists,mid+1,right);
        return merge(l1,l2);
    }

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if(lists.size() == 0) return nullptr;
        //暴力
        /*vector vec;
        for(auto it:lists){
            ListNode* cur = it;
            while(cur != nullptr){
                vec.push_back(cur);
                cur = cur->next;
            }
        }
        sort(vec.begin(),vec.end(),cmp);
        ListNode* h = new ListNode(0);
        ListNode* tmp = h;
        for(int i = 0; i < vec.size(); ++i){
            tmp->next = vec[i];
            tmp = tmp->next;
        }
        //最后一行是关键!!因为vec里的结点比如最大的结点5(也就是最后一个)的next不一定是null,会形成环
        tmp->next = nullptr;
        return h->next;*/

        //多路归并
        return qiefen(lists,0,lists.size()-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* merge(ListNode* l1, ListNode* l2){
        if(l1 == nullptr) return l2;
        if(l2 == nullptr) return l1;

        ListNode* head = new ListNode(0);
        ListNode* cur = head;
        while(l1!=nullptr && l2!=nullptr){
            if(l1->val <= l2->val){
                cur->next = l1;
                l1 = l1->next;
            }
            else{
                cur->next = l2;
                l2 = l2->next;
            }
            cur = cur->next;
        }
        cur->next = l1==nullptr?l2:l1;
        return head->next;
    }
    ListNode* qiefen(int left,int right,vector<ListNode*>& lists){
        if(left == right) return lists[left];
        int mid = left + (right-left)/2;

        //这里是左闭右闭,这里会一直递归切分下去,直到切分到left==right了,就开始merge了,然后上一层会merge下一层已经merge完的两个有序链表
        ListNode* l = qiefen(left,mid,lists);
        ListNode* r = qiefen(mid+1,right,lists);

        return merge(l,r);
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        //指针数组,每个指针指向一条链表
        //多路归并完全没毛病,因为每条链表都是有序的,所以当数组切分到一个指针也就是一条链表时等于是有序的,就可以进行归并了,
        if(lists.size() == 0) return nullptr;
        return qiefen(0,lists.size()-1,lists);
    }
};
/**
 * 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* merge_sort(vector<ListNode*>& lists,int l, int r){
        if(l == r) return lists[l];
        int mid = l + (r-l)/2;
        ListNode* left = merge_sort(lists,l,mid);
        ListNode* right =  merge_sort(lists,mid+1,r);

        //接下来就是合并,合并的是在深层次的递归中已经合并好的链表
        ListNode* h = new ListNode(0);
        ListNode* cur = h;
        while(left != nullptr && right != nullptr){
            if(left->val <= right->val){
                cur->next = left;
                left = left->next;
                cur = cur->next;
            }
            else{
                cur->next = right;
                right = right->next;
                cur = cur->next;
            }
        }
        cur->next = (left == nullptr)?right:left;
        return h->next;
    }
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        //因为数组中每一个元素都是一个有序链表,我们可以用归并排序,当切分到一个元素的时候向上进行合并,和切分到一个元素时认为有序一样
        if(lists.size() == 0) return nullptr;
        //不需要辅助数组,我们不改变原数组的值
        return merge_sort(lists,0,lists.size()-1);
    }
};

你可能感兴趣的:(#,链表,leetcode,#,排序算法,链表,单链表,归并排序,算法,leetcode)