zoukankan      html  css  js  c++  java
  • 【LeetCode-链表】合并K个排序链表

    题目描述

    合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
    示例:

    输入:
    [
      1->4->5,
      1->3->4,
      2->6
    ]
    输出: 1->1->2->3->4->4->5->6
    

    题目链接: https://leetcode-cn.com/problems/merge-k-sorted-lists/

    思路1

    使用优先队列也就是小根堆来做。队列中的元素类型为pair<ListNode*>,这里需要自定义比较函数将 ListNode* 按值从小到大排在优先队列中,值小的在队头,值大的在队尾。首先将每个链表的链表头入队(如果不空的话)。然后弹出队头元素,将队头元素加入到新链表中,将队头元素的下一个元素加入到队列中(如果不为空)。这样循环,直到队列为空。代码如下:

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    struct Compare{
        bool operator()(ListNode* p1, ListNode* p2){
            return p1->val > p2->val;
        }
    };
    class Solution {
    public:
        ListNode* mergeKLists(vector<ListNode*>& lists) {
            if(lists.empty()) return nullptr;
    
            priority_queue<ListNode*, vector<ListNode*>, Compare> q;
            for(ListNode* list:lists){
                if(list!=nullptr) q.push(list);
            }
    
            ListNode* head = new ListNode(0);
            ListNode* curNode = head;
            while(!q.empty()){
                auto node = q.top(); q.pop();
                curNode->next = node; 
                curNode = curNode->next;
                if(node->next!=nullptr) q.push(node->next);
            }
            return head->next;
        }
    };
    

    这里需要注意比较函数的写法。

    • 时间复杂度:O(nk)
    • 空间复杂度:O(n)

    思路2

    使用合并两个有序链表中的方法逐个合并链表。代码如下:

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    struct Compare{
        bool operator()(ListNode* p1, ListNode* p2){
            return p1->val > p2->val;
        }
    };
    class Solution {
    public:
        ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {  // 合并两个链表
            if(l1==nullptr) return l2;
            if(l2==nullptr) return l1;
    
            ListNode* head = new ListNode(0);
            ListNode* curNode = head;
            while(l1 && l2){
                if(l1->val < l2->val){
                    curNode->next = l1;
                    l1 = l1->next;
                }else{
                    curNode->next = l2;
                    l2 = l2->next;
                }
                curNode = curNode->next;
            }
            if(l1==nullptr) curNode->next = l2;
            if(l2==nullptr) curNode->next = l1;
            return head->next;
        }
    
        ListNode* mergeKLists(vector<ListNode*>& lists) {
            if(lists.empty()) return nullptr;
    
            ListNode* head = nullptr;
            for(auto list:lists){
                head = mergeTwoLists(head, list);
            }
            return head;
        }
    };
    
    • 时间复杂度:O(nk)
    • 空间复杂度:O(1)

    思路3

    使用类似归并排序的思想。代码如下:

    /**
     * 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) {
            if(lists.empty()) return nullptr;
    
            return mergeSort(lists, 0, lists.size()-1);
        }
    
        ListNode* mergeSort(vector<ListNode*> lists, int left, int right){
            if(left==right) return lists[left];
    
            int mid = left + (right-left)/2;
            ListNode* list1 = mergeSort(lists, left, mid);
            ListNode* list2 =  mergeSort(lists, mid+1, right);
            return mergeTwoList(list1, list2);
        }
    
        ListNode* mergeTwoList(ListNode* list1, ListNode* list2){
            if(list1==nullptr) return list2;
            if(list2==nullptr) return list1;
    
            ListNode* dummy = new ListNode(0);
            ListNode* cur = dummy;
            while(list1!=nullptr && list2!=nullptr){
                if(list1->val<list2->val){
                    cur->next = list1;
                    list1 = list1->next;
                }else{
                    cur->next = list2;
                    list2 = list2->next;
                }
                cur = cur->next;
            }
            if(list1!=nullptr) cur->next = list1;
            if(list2!=nullptr) cur->next = list2;
    
            return dummy->next;
        }
    };
    
  • 相关阅读:
    Oracle11g聚合函数
    和为S的连续正数数列,动态规划,C++
    统计一个数组在排序数组中出现的次数,C++,二分查找
    寻找两个链表的第一个公共子节点,C++
    二维数组中的查找
    数组中的逆序对,C++,分治算法
    得到从小到大的第N个丑数的三种方式(C++)一维动态规划
    连续字数组的最大和(Java)一个int数组,求其中的最大的连续数的和
    n个整数,求这中间最小的k个整数(Java)
    两个字符串的最长公共子串求法(C++、动态规划)
  • 原文地址:https://www.cnblogs.com/flix/p/13062514.html
Copyright © 2011-2022 走看看