Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【Day 87 】2021-12-05 - 23.合并 K 个排序链表 #106

Open
azl397985856 opened this issue Dec 4, 2021 · 86 comments
Open

【Day 87 】2021-12-05 - 23.合并 K 个排序链表 #106

azl397985856 opened this issue Dec 4, 2021 · 86 comments

Comments

@azl397985856
Copy link
Contributor

23.合并 K 个排序链表

入选理由

暂无

题目地址

https://leetcode-cn.com/problems/merge-k-sorted-lists/

前置知识

  • 链表
  • 分而治之

题目描述

给你一个链表数组每个链表都已经按升序排列请你将所有链表合并到一个升序链表中返回合并后的链表。

 

示例 1输入lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到1->1->2->3->4->4->5->6
示例 2输入lists = []
输出:[]
示例 3输入lists = [[]]
输出:[]
 

提示k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i]  升序 排列
lists[i].length 的总和不超过 10^4
@yanglr
Copy link

yanglr commented Dec 4, 2021

思路:

根据题意, 有点归并、分治的感觉, 可以用堆排序来做。

方法: 堆排序

借助priority_queue, 使用node的val构造一个小顶堆。
创建虚拟头结点,取出最小值对应的结点指针,将其挂接在游标指针上。
只要挂接点后面还有结点,则将其压入栈,继续从中拿出最小值,循环往复。

代码:

实现语言: C++

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if (lists.empty())
            return nullptr;

        ListNode* res;
        auto cmp = [](ListNode* n1, ListNode* n2)
        {
            return n1->val > n2->val;
        };

        /* 使用node的val构造一个小顶堆 */
        priority_queue<ListNode*, vector<ListNode*>, decltype(cmp)> nodesQ(cmp);
        for (auto& list : lists)
        {
            if (list != nullptr)
            {
                nodesQ.push(list);
            }
        }

        ListNode* fakeHead = new ListNode(-1);  /* 创建虚拟头结点 */
        ListNode* cur = fakeHead;
        while (!nodesQ.empty()) 
        {
            cur->next = nodesQ.top();  /* 取出最小值对应的结点指针,挂接在游标指针上 */
            cur = cur->next;
            nodesQ.pop();

            if (cur->next != nullptr)  /* 只要挂接点后面还有结点,则将其压入栈,继续从中拿出最小值,循环往复 */
            {
                nodesQ.push(cur->next);
            }
        }
        return fakeHead->next;
    }
};

复杂度分析:

  • 时间复杂度: O(N logN)
  • 空间复杂度: O(N)

@a244629128
Copy link

let numsArr = [];
  lists.forEach(item => {
    while(item && item.val !== null) {
      numsArr.push(item.val);
      item = item.next;
    }
  });
  numsArr = numsArr.sort((a, b) => b - a);
  let resultNode = null;
  numsArr.forEach(item => {
    let tempNode = new ListNode(item);
    tempNode.next = resultNode;
    resultNode = tempNode;
  })
  return resultNode;

@Laurence-try
Copy link

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        lenth = len(lists)

        # basic cases
        if lenth == 0: return None
        if lenth == 1: return lists[0]
        if lenth == 2: return self.mergeTwoLists(lists[0], lists[1])

        # divide and conqure if not basic cases
        mid = lenth // 2
        return self.mergeTwoLists(self.mergeKLists(lists[:mid]), self.mergeKLists(lists[mid:lenth]))


    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        res = ListNode(0)
        c1, c2, c3 = l1, l2, res
        while c1 or c2:
            if c1 and c2:
                if c1.val < c2.val:
                    c3.next = ListNode(c1.val)
                    c1 = c1.next
                else:
                    c3.next = ListNode(c2.val)
                    c2 = c2.next
                c3 = c3.next
            elif c1:
                c3.next = c1
                break
            else:
                c3.next = c2
                break

        return res.next

@ysy0707
Copy link

ysy0707 commented Dec 4, 2021

思路:堆排序

class Solution {
    //换一种写法,采用堆排序
    public ListNode mergeKLists(ListNode[] lists) {
        //创建一个堆,重写排序方式
        PriorityQueue<ListNode> queue = new PriorityQueue<ListNode>((o1, o2) -> o1.val - o2.val);
        //遍历链表数组,然后将每个链表的每个节点都放入堆中
        //最小堆会自动的把所有的节点从小到大排列
        for(int i = 0; i < lists.length; i++){
            while(lists[i] != null){
                queue.add(lists[i]);
                //还得把它们连接起来
                lists[i] = lists[i].next;
            }
        }
        //设置虚拟节点
        ListNode dummy = new ListNode(-1);
        ListNode head = dummy;
        //从堆中取出元素并连接起来
        while(!queue.isEmpty()){
            head.next = queue.poll();
            head = head.next;
        }
        head.next = null;
        return dummy.next;
    }
}

时间复杂度: O(NlogN)
空间复杂度: O(N)

@chenming-cao
Copy link

chenming-cao commented Dec 4, 2021

解题思路

堆。多路归并问题。建立小顶堆来储存所有非空链表的头节点。建立一个dummy节点来合并链表。每次从小顶堆取值最小的头节点,然后连到合并链表的尾部,之后更新头节点和链表尾部,如果头节点不是null,则放入堆中。如此循环直到堆为空。最后返回合并好的链表的头节点dummy.next即可。

代码

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        // use min-heap to store the head nodes from the k linked-list, sorted by value of the node
        PriorityQueue<ListNode> heap = new PriorityQueue<>((a, b) -> a.val - b.val);
        // put nodes in heap
        for (ListNode list : lists) {
            // only put non-empty list in the heap
            if (list != null) heap.offer(list);
        }
        ListNode dummy = new ListNode();
        ListNode cur = dummy;
        while (!heap.isEmpty()) {
            // get the head with smallest value and connect to the tail of merged list
            ListNode head = heap.poll();
            cur.next = head;
            cur = cur.next;
            // update head to the list and put a new head into heap if the new head is not null
            head = head.next;
            if (head != null) heap.offer(head);
        }
        return dummy.next;
    }
}

复杂度分析

  • 时间复杂度:O(knlogk),k为链表数,k*n为所有链表的总节点数
  • 空间复杂度:O(k),堆中储存k个链表的头节点

@zjsuper
Copy link

zjsuper commented Dec 4, 2021

class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        if not lists:
            return None
        elif len(lists) == 1:
            return lists[0]
        elif len(lists) == 2:
            return self.merge_two(lists[0],lists[1])
        
        mid = len(lists)//2
        return self.merge_two(self.mergeKLists(lists[:mid]),self.mergeKLists(lists[mid:]))
    
    def merge_two(self,l1,l2):
        res= ListNode(0)
        c = res

        while l1 and l2:
            if l1.val<=l2.val:
                c.next = ListNode(l1.val)
                c = c.next
                l1= l1.next
            else:
                c.next = ListNode(l2.val)
                c = c.next
                l2 = l2.next
        if l1:
            c.next = l1
        elif l2:
            c.next = l2
        return res.next

@pophy
Copy link

pophy commented Dec 4, 2021

思路

  • PriorityQueue
    • 如果PQ不空 就依次弹出当前最小值 cur
    • 如果cur.next不空 把cur.next放入PQ

Java Code

    public ListNode mergeKLists(ListNode[] lists) {
        PriorityQueue<ListNode> pq = new PriorityQueue<>((a,b) -> a.val - b.val);
        ListNode dummy = new ListNode(0);
        for (ListNode node : lists) {
            if (node != null) {
                pq.add(node);
            }
        }
        ListNode p = dummy;
        while (!pq.isEmpty()) {
            ListNode cur = pq.poll();
            p.next = cur;
            p = p.next;
            if (cur.next != null) {
                pq.add(cur.next);
            }
        }
        return dummy.next;
    }

时间&空间

  • 时间 O(nlog(n))
  • 空间 O(n)

@zhangzz2015
Copy link

思路

  • 利用heap + merge sort实现 k 路合并有序数组,是一个标准的做法,对于非链表类型,有时候要找到第k个,也可采用二分。时间复杂度为O(n logk),空间复杂度为O(k)。

关键点

代码

  • 语言支持:C++

C++ Code:

/**
 * 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* mergeKLists(vector<ListNode*>& lists) {
        
        
auto comp = [](ListNode* & node1, ListNode* & node2 ) {return node1->val> node2->val;};         
       priority_queue<ListNode*, vector<ListNode*>, decltype(comp)>  pq(comp);  
        
        for(int i=0;i < lists.size(); i++)
        {
           if(lists[i]) 
            pq.push(lists[i]); 
        }
        ListNode* prev = NULL; 
        ListNode* ret = NULL; 
        while(pq.size())
        {
            ListNode* topNode = pq.top(); 
            pq.pop(); 
            if(prev == NULL)
                ret = topNode; 
            else
                prev->next = topNode; 
            
            if(topNode->next)
                pq.push(topNode->next); 
            
            prev = topNode; 
        }
        
        return ret; 
        
    }
};

@XinnXuu
Copy link

XinnXuu commented Dec 4, 2021

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        return merge(lists, 0, lists.length - 1);
    }

    public ListNode merge (ListNode[] lists, int l, int r){
        if (l == r){
            return lists[r];
        }
        if (l > r){
            return null;
        }
        int mid = (l + r) >> 1;
        return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
    }

    public ListNode mergeTwoLists(ListNode l1, ListNode l2){
        // if (l1 == null || l2 == null) {
        //     return l1 != null ? l1 : l2;
        // }
        ListNode dummy = new ListNode(0);
        ListNode tail = dummy;
        ListNode aPtr = l1, bPtr = l2;
        while (aPtr != null && bPtr != null){
            if (aPtr.val < bPtr.val){
                tail.next = aPtr;
                aPtr = aPtr.next;
            } else {
                tail.next = bPtr;
                bPtr = bPtr.next;
            }
            tail = tail.next;
        }
        if (aPtr != null){
            tail.next = aPtr;
        } else {
            tail.next = bPtr;
        }
        return dummy.next;
    }
}

@leungogogo
Copy link

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }
        PriorityQueue<ListNode> heap = new PriorityQueue<>(lists.length, (n1, n2) -> {
            if (n1.val > n2.val) {
                return 1;
            } else {
                return -1;
            }
        });
        
        for (int i = 0; i < lists.length; ++i) {
            if (lists[i] != null)
                heap.offer(lists[i]);
        }
        
        ListNode dummy = new ListNode(-1);
        ListNode cur = dummy;
        while (!heap.isEmpty()) {
            ListNode node = heap.poll();
            cur.next = node;
            if (node.next != null) {
                heap.offer(node.next);
            }
            cur = cur.next;
        }
        return dummy.next;
    }
}

@skinnyh
Copy link

skinnyh commented Dec 4, 2021

Solution

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        dummy = ListNode()
        prev = dummy
        q = []
        for idx, n in enumerate(lists):
            if n:
                heapq.heappush(q, (n.val, idx, n))
        while q:
            _, idx, n = heapq.heappop(q)
            if n.next:
                heapq.heappush(q, (n.next.val, idx, n.next))
            prev.next = n
            prev = n
        return dummy.next

Time complexity: O(NlogK) N is the total number of nodes. K=len(lists)

Space complexity: O(K)

@xj-yan
Copy link

xj-yan commented Dec 4, 2021

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
import heapq

class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        curt = dummy = ListNode(0)
        heap = []
        count = 0
        for node in lists:
            if node is not None:
                count += 1
                heapq.heappush(heap, (node.val, count, node))
        while len(heap) > 0:
            _, _, curt.next = heapq.heappop(heap)
            curt = curt.next
            if curt.next is not None:
                count += 1
                heapq.heappush(heap, (curt.next.val, count, curt.next))
        return dummy.next

Time Complexity: O(nlogn), Space Complexity: O(n)

@littlemoon-zh
Copy link

littlemoon-zh commented Dec 4, 2021

def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
    memo = {idx: x for idx, x in enumerate(lists)}
    q = [[x.val, idx] for idx, x in  enumerate(lists) if x]
    heapify(q)
    cur = dummy = ListNode(0)
    
    while q:
        _, idx = heappop(q)
        node = memo[idx]
        cur.next = node
        if node.next:
            heappush(q, [node.next.val, idx])
            memo[idx] = node.next
        cur = cur.next
    
    return dummy.next

@siyuelee
Copy link

siyuelee commented Dec 4, 2021

heap

class Solution(object):
    def mergeKLists(self, lists):
        import heapq
        dummy = ListNode(0)
        p = dummy
        head = []
        for i in range(len(lists)):
            if lists[i] :
                # print lists[i].val, i
                heapq.heappush(head, (lists[i].val, i))
                # print head
                lists[i] = lists[i].next
        while head:
            val, idx = heapq.heappop(head)
            # print head
            p.next = ListNode(val)
            p = p.next
            if lists[idx]:
                # print idx, lists[idx]
                heapq.heappush(head, (lists[idx].val, idx))
                # print head
                lists[idx] = lists[idx].next
        return dummy.next

T: O(NlogK) N is the total num of all nodes, K is the num of lists
S: O(K)

@kennyxcao
Copy link

23. Merge k Sorted Lists

Intuition

  • Heap

Code

/**
 * @param {ListNode[]} lists
 * @return {ListNode}
 */
const mergeKLists = function(lists) {
  const dummy = new ListNode(0);
  let current = dummy;
  const minHeap = new BinaryHeap((c, p) => c.val > p.val);
  for (const head of lists) {
    if (head) minHeap.push(head);
  }
  while (minHeap.size() > 0) {
    const minNode = minHeap.pop();
    current.next = minNode;
    current = current.next;
    if (minNode.next) minHeap.push(minNode.next);
  }
  return dummy.next;
};

Complexity Analysis

  • Time: O(nlogk)
  • Space: O(k)

@Daniel-Zheng
Copy link

思路

分治。

代码(C++)

class Solution {
public:
    ListNode* mergeTwoLists(ListNode *a, ListNode *b) {
        if ((!a) || (!b)) return a ? a : b;
        ListNode head, *tail = &head, *aPtr = a, *bPtr = b;
        while (aPtr && bPtr) {
            if (aPtr->val < bPtr->val) {
                tail->next = aPtr; aPtr = aPtr->next;
            } else {
                tail->next = bPtr; bPtr = bPtr->next;
            }
            tail = tail->next;
        }
        tail->next = (aPtr ? aPtr : bPtr);
        return head.next;
    }

    ListNode* merge(vector <ListNode*> &lists, int l, int r) {
        if (l == r) return lists[l];
        if (l > r) return nullptr;
        int mid = (l + r) >> 1;
        return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
    }

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        return merge(lists, 0, lists.size() - 1);
    }
};

复杂度分析

  • 时间复杂度:O(KN*LogK)
  • 空间复杂度:O(LogK)

@ZacheryCao
Copy link

Idea:

Heap

Code:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        if not lists:
            return None
        heap = []
        for i in range(len(lists)):
            if lists[i]:
                heapq.heappush(heap, (lists[i].val, i, lists[i]))
        head = ListNode(0)
        dummy = head
        while heap:
            _, i, dummy.next = heapq.heappop(heap)
            dummy = dummy.next
            if dummy.next:
                heapq.heappush(heap, (dummy.next.val, i, dummy.next))
        return head.next

Complexity:

Time: O(N log K)
Space: O(K)

@pan-qin
Copy link

pan-qin commented Dec 5, 2021

Idea:

divide and conquer

Complexity:

Time: O(Nlogk).
Space:O(logk)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if(lists.length == 0)
            return null;
        if(lists.length==1)
            return lists[0];
        return mergeSort(lists, 0, lists.length-1);
    }
    private ListNode mergeSort(ListNode[] lists, int start, int end) {
        if(start>=end)
            return lists[start];
        int mid = start+(end-start)/2;
        ListNode left = mergeSort(lists, start, mid);
        ListNode right = mergeSort(lists, mid+1, end);
        ListNode dummy = new ListNode(-1), tail = dummy;
        while(left != null || right != null) {
            int val1 = (left==null? Integer.MAX_VALUE:left.val);
            int val2 = (right == null? Integer.MAX_VALUE: right.val);
            if(val1<val2) {
                tail.next= left;
                left = left.next;
            }
            else {
                tail.next = right;
                right=right.next;
                
            }
            tail= tail.next;          
        }
        return dummy.next;
    }
}

@Victoria011
Copy link

基本思路

Divide & conquer, 不断两两合并

代码

class Solution:
    def merge(self, l, r):
        dummy = curr = ListNode(0)
        while l and r:
            if l.val < r.val:
                curr.next = l
                l = l.next
            else:
                curr.next = r
                r = r.next
            curr = curr.next
        curr.next = l or r
        return dummy.next
            
        
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        if not lists: return
        if len(lists) == 1:
            return lists[0]
        mid = len(lists) // 2
        left, right = self.mergeKLists(lists[:mid]), self.mergeKLists(lists[mid:])
        return self.merge(left, right)

复杂度分析

Time complexity: O(NlogK) 假设 K: num of lists, N 两list 总数, merge 两个list 时间复杂度为 O (N)

Space complexity: O(1)

@BlueRui
Copy link

BlueRui commented Dec 5, 2021

Problem 23. Merge k Sorted Lists

Algorithm

  • This problem can be solved using divide and conquer similar to merge sort.
  • Every time we divide the problem into two smaller problems until there are only one or two lists to merge.

Complexity

  • Time Complexity: O(NlogK), where N is the total number of nodes.
    • With merge sort, the divide time is O(N).
    • Merge time is O(N) on each level with O(logK) levels => O(NlogK).
  • Space Complexity: O(1), constant extra space required.

Code

Language: Java

public ListNode mergeKLists(ListNode[] lists) {
    if (lists == null || lists.length == 0) {
        return null;
    }
    merge(lists, 0, lists.length - 1);
    return lists[0];
}

private void merge(ListNode[] lists, int left, int right) {
    // Merge lists from index left to right, and save merged list to index left
    if (left == right) {
        return;
    }
    int mid = left + (right - left) / 2;
    merge(lists, left, mid);
    merge(lists, mid + 1, right);

    // Merge the two lists on left and mid + 1
    ListNode dummy = new ListNode();
    ListNode cur = dummy;
    ListNode l1 = lists[left];
    ListNode l2 = lists[mid + 1];

    while (l1 != null && l2 != null) {
        if (l1.val <= l2.val) {
            cur.next = l1;
            cur = cur.next;
            l1 = l1.next;
        } else {
            cur.next = l2;
            cur = cur.next;
            l2 = l2.next;
        }
    }
    // Handle remaining of 1l or l2 and attach to the merged list
    if (l1 != null) {
        cur.next = l1;
    }
    if (l2 != null) {
        cur.next = l2;
    }
    // Set the merged list to index left
    lists[left] = dummy.next;
}

@yan0327
Copy link

yan0327 commented Dec 5, 2021

func mergeKLists(lists []*ListNode) *ListNode {
    n := len(lists)
    if n == 0{
        return nil
    }
    if n == 1{
        return lists[0]
    }
    mid := n>>1
    return merge(mergeKLists(lists[:mid]),mergeKLists(lists[mid:]))
}

func merge(l1 *ListNode,l2 *ListNode) *ListNode{
    dummy := &ListNode{}
    cur := dummy
    for l1 != nil && l2 != nil{
        if l1.Val < l2.Val{
            cur.Next = l1
            l1 = l1.Next
        }else{
            cur.Next = l2
            l2 = l2.Next
        }
        cur = cur.Next
    }
    if l1 != nil{
        cur.Next = l1
    }
    if l2 != nil{
        cur.Next = l2
    }
    return dummy.Next
}

@joeytor
Copy link

joeytor commented Dec 5, 2021

思路

先把每个 list 中的第一个节点的值以及节点的 index 加入堆中

用一个哨兵节点当 head, 然后每次从堆中取出最小的节点与 head 相连接

如果这个节点有下一个节点, 那么将下一个节点的值和节点 index 继续加入堆中

最后返回哨兵节点 head 的下一个节点 head.next 是新链表的开头

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
import heapq

class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        def __lt__(self, other):
            return self.val < other.val   
        ListNode.__lt__ == __lt__
        print(ListNode.__lt__)
        h = []

        for node in lists:
            if node is not None:
                h.append(node)
        
        heapq.heapify(h)
        # dummy node
        head = ListNode()
        cur = head

        while h:
            node = heapq.heappop(h)
            cur.next = node
            cur = node

            if node.next is not None:
                heapq.heappush(h, node.next)
        
        return head.next

复杂度

时间复杂度: O(kn logk) heap 的大小最大为 k, 插入删除都是 O(logk), 最多有 kn 个点, 每个都被插入删除一次, 时间复杂度为 O(kn logk)

空间复杂度: 堆的空间复杂度为 O(k)

@akxuan
Copy link

akxuan commented Dec 5, 2021

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists.length == 0)
            return null;
        ListNode merged = null;
        for (ListNode head : lists) {
            merged = mergeTwoLists(merged, head);
        }
        return merged;
    }
    
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null)
            return l2;
        if (l2 == null)
            return l1;
        if (l1.val < l2.val) {
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        }
        else {
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }
}

只会暴力解...

@watermelonDrip
Copy link

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next

import heapq

class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        if len(lists) == 0:
            return None
        
       
        
        

        heap = []

        dummy = ListNode()
        cur = dummy

        # create k head heaps 
        for i in range(len(lists)):
            if not lists[i]:
                continue
            heapq.heappush(heap,[lists[i].val,i])
            lists[i] = lists[i].next
        
        # add new element
        
        while heap:
            [node, idx] = heapq.heappop(heap)
            cur.next = ListNode(node)
            cur = cur.next
            if lists[idx]:
                heapq.heappush(heap,[lists[idx].val,idx])
                lists[idx] = lists[idx].next
        return dummy.next

@mannnn6
Copy link

mannnn6 commented Dec 5, 2021

代码

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        return merge(lists, 0, lists.length - 1);
    }

    public ListNode merge(ListNode[] lists, int l, int r) {
        if (l == r) {
            return lists[l];
        }
        if (l > r) {
            return null;
        }
        int mid = (l + r) >> 1;
        return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
    }

    public ListNode mergeTwoLists(ListNode a, ListNode b) {
        if (a == null || b == null) {
            return a != null ? a : b;
        }
        ListNode head = new ListNode(0);
        ListNode tail = head, aPtr = a, bPtr = b;
        while (aPtr != null && bPtr != null) {
            if (aPtr.val < bPtr.val) {
                tail.next = aPtr;
                aPtr = aPtr.next;
            } else {
                tail.next = bPtr;
                bPtr = bPtr.next;
            }
            tail = tail.next;
        }
        tail.next = (aPtr != null ? aPtr : bPtr);
        return head.next;
    }
}

复杂度

时间复杂度: O(kn logk)

空间复杂度: O(logk)

@wenjialu
Copy link

wenjialu commented Dec 5, 2021

idea

初始化:把每个list里面的链表第一个节点放堆里面。
当堆还在的时候,弹出一个(pop出最小那个),放一个(在他所在list 找下一个节点)。
直到堆清空,排序完成。

code

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        # 优先队列
        import heapq
        dummy = ListNode(0)
        pointer = dummy
        head = []

        for idx in range(len(lists)):
            if lists[idx]:
                # print(lists[i].val) 
                heapq.heappush(head, (lists[idx].val, idx)) # 把每个list的头节点的值和列表中的下标记录到head中。
                lists[idx] = lists[idx].next # 链表去头。
   
        while head: 
            # print("round")
            val, idx = heapq.heappop(head)  # 把装进head里的从小到大拿出来。一次只拿一个。
            # print(val, idx)
            pointer.next = ListNode(val) # 串成链表    
            pointer = pointer.next
            if lists[idx]: # 最小那个拿出来之后,去它所在的list拿下一个放到名叫head的堆里
                heapq.heappush(head, (lists[idx].val, idx)) #把list的头节点的值和列表中的下标记录到head中。
                lists[idx] = lists[idx].next 

        return dummy.next

complexity

时间复杂度:O(kn*log(k)), n 是所有链表中元素的总和,k 是链表个数。
考虑优先队列中的元素不超过 k 个,那么插入和删除的时间代价为 O(logk),这里最多有 kn 个点,对于每个点都被插入删除各一次,故总的时间代价即渐进时间复杂度为 O(kn × logk)。

空间复杂度:优先队列中的元素不超过 k 个,故渐进空间复杂度为 O(k)

@kbfx1234
Copy link

kbfx1234 commented Dec 5, 2021

23. 合并K个升序链表

// 12-5 cpp
class Solution
{
public:
    ListNode* merge(ListNode * list1, ListNode * list2)
    {
        if (!list1)
            return list2;
        if (!list2)
            return list1;
        if (list1->val <= list2->val)
        {
            list1->next = merge(list1->next, list2);
            return list1;
        }
        else
        {
            list2->next = merge(list1, list2->next);
            return list2;
        }
    }
    ListNode* mergeKLists(vector<ListNode *> &lists)
    {
        if (lists.size() == 0)
            return nullptr;
        ListNode *head = lists[0];
        for (int i = 1; i < lists.size(); i++)
        {
            if (lists[i])
                head = merge(head, lists[i]);
        }
        return head;
    }
};

@Bingbinxu
Copy link

思路
构建一个小顶堆,重写排序方法,将每个链表的第一个元素放到小顶堆
依次取出最小值,直到没有next
代码(C++)

实现语言: C++
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if(lists.empty())
        return nullptr;
        ListNode *res;
        //重定义比较方式
        auto cmp = [](ListNode* n1, ListNode* n2)
        {
            return n1->val>n2->val;
        }
        priority_queue<ListNode*, vector<ListNode*>, decltype(cmp)> k(cmp);
        for (auto& list : lists)
        {
            if (list != nullptr)
            {
                k.push(list);
            }
        }
        ListNode* fakeHead = new ListNode(-1);  /* 创建虚拟头结点 */
        ListNode* cur = fakeHead;
        while (!k.empty()) 
        {
            cur->next = k.top();  
            cur = cur->next;
            k.pop();

            if (cur->next != nullptr)  
            {
                k.push(cur->next);
            }
        }
        return fakeHead->next;
    }
};

复杂度分析
时间复杂度: O(NlogN)
空间复杂度: O(N)

@ginnydyy
Copy link

ginnydyy commented Dec 5, 2021

Problem

https://leetcode.com/problems/merge-k-sorted-lists/

Notes

  • heap

Solution

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if(lists == null || lists.length == 0){
            return null;
        }
        
        PriorityQueue<ListNode> q = new PriorityQueue<>((n1, n2) -> n1.val - n2.val);
        
        ListNode dummy = new ListNode();
        ListNode tail = dummy;
        
        for(ListNode node: lists){
            if(node != null){
                q.offer(node);
            }
        }
        
        while(!q.isEmpty()){
            ListNode cur = q.poll();
            tail.next = cur;
            tail = tail.next;
            if(cur.next != null){
                q.offer(cur.next);
            }
        }
        
        return dummy.next;
        
    }
}

Complexity

  • T: O(k * n * logk). k is the length of the given lists, n is the average size of the k lists. Each heap offer operation costs O(logk), there are k * n nodes, so overall isO(k * n * logk).
  • S: O(k), for the heap.

@L-SUI
Copy link

L-SUI commented Dec 5, 2021

/**

  • Definition for singly-linked list.
  • function ListNode(val, next) {
  • this.val = (val===undefined ? 0 : val)
    
  • this.next = (next===undefined ? null : next)
    
  • }
    /
    /
    *
  • @param {ListNode[]} lists
  • @return {ListNode}
    /
    /
    *
  • @param {ListNode[]} lists
  • @return {ListNode}
    */
    var mergeKLists = function (lists) {
    // 当是空数组的情况下
    if (!lists.length) {
    return null;
    }
    // 合并两个排序链表
    const merge = (head1, head2) => {
    let dummy = new ListNode(0);
    let cur = dummy;
    // 新链表,新的值小就先接谁
    while (head1 && head2) {
    if (head1.val < head2.val) {
    cur.next = head1;
    head1 = head1.next;
    } else {
    cur.next = head2;
    head2 = head2.next;
    }
    cur = cur.next;
    }
    // 如果后面还有剩余的就把剩余的接上
    cur.next = head1 == null ? head2 : head1;
    return dummy.next;
    };
    const mergeLists = (lists, start, end) => {
    if (start + 1 == end) {
    return lists[start];
    }
    // 输入的k个排序链表,可以分成两部分,前k/2个链表和后k/2个链表
    // 如果将这前k/2个链表和后k/2个链表分别合并成两个排序的链表,再将两个排序的链表合并,那么所有链表都合并了
    let mid = (start + end) >> 1;
    let head1 = mergeLists(lists, start, mid);
    let head2 = mergeLists(lists, mid, end);
    return merge(head1, head2);
    };
    return mergeLists(lists, 0, lists.length);
    };

@asterqian
Copy link

思路

min heap

代码

/**
 * 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 comp {
public:
    bool operator() (ListNode * a, ListNode * b) {
        return a->val > b->val;
    }
};
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        priority_queue<ListNode*, vector<ListNode*>, comp> pq;
        // push all the heads in the lists
        for (ListNode* node: lists) {
            if (node) {
                pq.push(node);
            }
            
        }
        ListNode* dummyHead = new ListNode(-1);
        ListNode* temp = dummyHead;

        while (!pq.empty()) {
            ListNode* curr = pq.top();
            pq.pop();
            temp->next = curr;
            temp = temp->next;
            // check the remaining
            if (curr->next) {
                pq.push(curr->next);
            }
        }
        return dummyHead->next;
    }
};
时间复杂度 O(nklogk) n is the number of nodes, k is the number of lists
空间复杂度 O(k)

@BreezePython
Copy link

思路

堆排序

代码

class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        def __lt__(self,other):
            return self.val < other.val
        ListNode.__lt__ = __lt__
        heap = []
        for i in lists:
            if i :heapq.heappush(heap,i)
        d = c = ListNode(-1)
        while heap:
            n = heapq.heappop(heap)
            c.next = n
            c = c.next
            n = n.next
            if n:heapq.heappush(heap,n)
        return d.next

复杂度

  • 时间复杂度:O(NlogN)
  • 空间复杂度:O(K)

@freedom0123
Copy link

class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        dummy_head=ListNode()
        tail = dummy_head
        lists = list(filter(lambda x: x is not None, lists))
        
        hp = []
        for head in lists:
            while head:
                heapq.heappush(hp, head.val)
                head = head.next
        
        while hp:
            val = heapq.heappop(hp)
            tail.next = ListNode(val)
            tail = tail.next
        
        return dummy_head.next

@chun1hao
Copy link

chun1hao commented Dec 5, 2021

const merge = function (list1: ListNode, list2: ListNode): ListNode {
  let head: ListNode = new ListNode(0);
  let dummyHead: ListNode = head;
  while (list1 && list2) {
    if (list1.val < list2.val) {
      dummyHead.next = list1;
      list1 = list1.next;
    } else {
      dummyHead.next = list2;
      list2 = list2.next;
    }
    dummyHead = dummyHead.next;
  }
  if (list1) dummyHead.next = list1;
  if (list2) dummyHead.next = list2;
  return head.next;
};
function mergeKLists(lists: Array<ListNode | null>): ListNode | null {
  let len: number = lists.length;
  if (len === 0) return null;
  if (len < 2) return lists[0];
  let mid = Math.floor(len / 2);
  let left = mergeKLists(lists.slice(0, mid));
  let right = mergeKLists(lists.slice(mid));
  return merge(left, right);
}

@user1689
Copy link

user1689 commented Dec 5, 2021

题目

https://leetcode-cn.com/problems/merge-k-sorted-lists/

思路

Heap

python3

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        # time nlogn
        # space n
        # heapq
        # 遍历lists加入所有node的值 python默认最小堆直接弹出后串起来即可
        heap = []
        for node in lists:
            while node:
                heapq.heappush(heap, node.val)
                node = node.next
        
        dummy = ListNode(0, None)
        cur = dummy
        while heap:
            Val = heapq.heappop(heap)
            cur.next = ListNode(Val, None)
            cur = cur.next
        return dummy.next
        
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        # time nlogn
        # space n
        heap = []
        # for i, node in enumerate(lists):
        #     if node:
        #         heapq.heappush(heap, (node.val, i))
        for i in range(0, len(lists)):
            if lists[i]:
                heapq.heappush(heap, (lists[i].val, i))

        if not heap: return None
        dummy = ListNode(0, None)
        cur = dummy

        while heap:
            val, idx = heapq.heappop(heap)
            cur.next = ListNode(val, None)
            cur = cur.next
            lists[idx] = lists[idx].next
            if lists[idx]:
                heapq.heappush(heap, (lists[idx].val, idx))
        return dummy.next        

复杂度分析

  • time nlogn
  • space n

相关题目

  1. 待补充

@asaoba
Copy link

asaoba commented Dec 5, 2021

之前同学面试遇到的高频题,又做了一遍

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
 //整体思路:基于合并两个排序链表的方法,延伸为合并k个排序链表
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        return merge(lists,0,lists.length-1);
    }

    public ListNode merge(ListNode[] lists,int l,int r){
        //分治算法函数
        if(l==r)
          return lists[l];
        if(l>r)
          return null;
        int mid=(l+r)/2;
        return mergeTwoLists(merge(lists,l,mid),merge(lists,mid+1,r));//递归实现分治,这里需要再理解
    }


    public ListNode mergeTwoLists(ListNode a,ListNode b){
        if(a==null||b==null){
            return a!=null?a:b;
        }
        ListNode head=new ListNode(0);//这里不能定义为null,null节点就没有next等属性用来操作了
        ListNode curr=head;
        ListNode aPtr=a;
        ListNode bPtr=b;
        while(aPtr!=null&&bPtr!=null){
            if(aPtr.val<bPtr.val){
                curr.next=aPtr;
                aPtr=aPtr.next;
            }
            else{
                curr.next=bPtr;
                bPtr=bPtr.next;
            }
            curr=curr.next;
        }
        curr.next=aPtr!=null?aPtr:bPtr;        
        return head.next;
    }
}

@chaggle
Copy link

chaggle commented Dec 5, 2021


title: "Day 87 23. 合并K个升序链表"
date: 2021-12-05T21:29:57+08:00
tags: ["Leetcode", "c++", "heap"]
categories: ["91-day-algorithm"]
draft: true


23. 合并K个升序链表

题目

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

 

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
  1->4->5,
  1->3->4,
  2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
示例 2:

输入:lists = []
输出:[]
示例 3:

输入:lists = [[]]
输出:[]
 

提示:

k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i] 按 升序 排列
lists[i].length 的总和不超过 10^4

题目思路

  • 1、本题目day69日有使用分治的思想做题,今日使用大顶堆解决问题。(非手写堆,这两日时间花费有些多,故今日不写)
/**
 * 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* mergeKLists(vector<ListNode*>& lists) {
        auto min = [](ListNode *a, ListNode *b) 
        { 
            return a -> val > b -> val; 
            };
        priority_queue<ListNode*, vector<ListNode*>, decltype(min)> ans(min);
        auto *root = new ListNode();
        for(auto p:  lists) 
        {
            if(p != nullptr) ans.push(p);
        }
        ListNode *cur = root;
        while(!ans.empty()) 
        {
            ListNode *tmp = ans.top(); ans.pop();
            if(tmp -> next != nullptr) ans.push(tmp->next);
            tmp -> next = cur -> next;
            cur -> next = tmp;
            cur = cur -> next;
        }
        return root -> next;
    }
};

复杂度

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

@ChenJingjing85
Copy link

class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        def mergeTwoLists(root1, root2):
            n1 = root1
            n2 = root2
            tempHead = ListNode(0)
            head = tempHead
            while (n1 != None and n2 != None):
                if n1.val < n2.val:
                    tempHead.next = n1
                    n1 = n1.next
                else:
                    tempHead.next = n2
                    n2 = n2.next
                tempHead = tempHead.next
            tempHead.next = n1 if n2 == None else n2
            return head.next

        if not lists:
             return None
        if len(lists) <= 1:
            return lists[0]       
        merged = mergeTwoLists(lists[0], lists[1])
        for i in range(2, len(lists)):
            merged = mergeTwoLists(merged, lists[i])
        return merged
            

@Yufanzh
Copy link

Yufanzh commented Dec 5, 2021

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        dummy = ListNode(0)
        curr = dummy
        heap = [(head.val, i, head) for (i, head) in enumerate(lists) if head]
        heapify(heap)
        
        while heap:
            val, i, node = heapq.heappop(heap)
            curr.next = node
            curr = curr.next
            if node.next:
                heapq.heappush(heap, (node.next.val, i, node.next))
        
        return dummy.next

Complexity Analysis

  • Time complexity: O(Nlogk)
  • Space complexity: O(K)

@yj9676
Copy link

yj9676 commented Dec 5, 2021

public ListNode mergeTwoLists(ListNode a, ListNode b) {
    if (a == null || b == null) {
        return a != null ? a : b;
    }
    ListNode head = new ListNode(0);
    ListNode tail = head, aPtr = a, bPtr = b;
    while (aPtr != null && bPtr != null) {
        if (aPtr.val < bPtr.val) {
            tail.next = aPtr;
            aPtr = aPtr.next;
        } else {
            tail.next = bPtr;
            bPtr = bPtr.next;
        }
        tail = tail.next;
    }
    tail.next = (aPtr != null ? aPtr : bPtr);
    return head.next;
}

@15691894985
Copy link

【day87】题目地址(23. 合并 K 个排序链表)与69日分治板块题相同

https://leetcode-cn.com/problems/merge-k-sorted-lists/

采用python小顶堆做:加入所有Node ,一个个输出即可

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        heap = []
        for list1 in lists:
            while list1:
                heapq.heappush(heap, list1.val)
                list1 = list1.next
        
        dummy = ListNode(0, None)
        cur = dummy
        while heap:
            VALUE = heapq.heappop(heap)
            cur.next = ListNode(VALUE, None)
            cur = cur.next
        return dummy.next

复杂度分析:

时间复杂度:O(knlogn) 堆中的元素不超过K个,n个链表,每个元素的偶被插入删除一次logn

空间复杂度:O(k)

@yibenxiao
Copy link

【Day 87】23.合并 K 个排序链表

代码

/**
 * 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:
    struct Status {
        int val;
        ListNode *ptr;
        bool operator < (const Status &rhs) const {
            return val > rhs.val;
        }
    };

    priority_queue <Status> q;

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        for (auto node: lists) {
            if (node) q.push({node->val, node});
        }
        ListNode head, *tail = &head;
        while (!q.empty()) {
            auto f = q.top(); q.pop();
            tail->next = f.ptr; 
            tail = tail->next;
            if (f.ptr->next) q.push({f.ptr->next->val, f.ptr->next});
        }
        return head.next;
    }
};

@taoyr722
Copy link

taoyr722 commented Dec 5, 2021

代码

class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        if not lists:
            return None
        tmp = ListNode(-1)
        x = tmp
        tmp2 = []
        for i in lists:
            p = i
            while p != None:
                tmp2.append(p.val)
                p = p.next
        tmp2.sort()
        for i in tmp2:
            k = ListNode(i)
            x.next = k
            x = x.next
        return tmp.next

@dongzegithub
Copy link

public ListNode mergeTwoLists(ListNode a, ListNode b) {
    if (a == null || b == null) {
        return a != null ? a : b;
    }
    ListNode head = new ListNode(0);
    ListNode tail = head, aPtr = a, bPtr = b;
    while (aPtr != null && bPtr != null) {
        if (aPtr.val < bPtr.val) {
            tail.next = aPtr;
            aPtr = aPtr.next;
        } else {
            tail.next = bPtr;
            bPtr = bPtr.next;
        }
        tail = tail.next;
    }
    tail.next = (aPtr != null ? aPtr : bPtr);
    return head.next;
}

@CoreJa
Copy link

CoreJa commented Dec 5, 2021

思路

老题了,归并分治做法,一会儿再试试堆的做法,复杂度是nklogk

代码

    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        if len(lists) == 0:
            return None
        elif len(lists) == 1:
            return lists[0]
        elif len(lists) == 2:
            left = lists[0]
            right = lists[1]
            ans = ListNode()
            p = ans
            while left and right:
                if left.val <= right.val:
                    p.next = left
                    left = left.next
                else:
                    p.next = right
                    right = right.next
                p = p.next
            p.next = left if left else right
            return ans.next
        else:
            n = len(lists)
            return self.mergeKLists([self.mergeKLists(lists[:n // 2]), self.mergeKLists(lists[n // 2:])])

@Zhang6260
Copy link

JAVA版本

直接使用了堆排序。

class Solution {
   public ListNode mergeKLists(ListNode[] lists) {
       PriorityQueue<ListNode> queue = new PriorityQueue<>()(new Comparator<Integer>() {
           @Override
           public int compare(ListNode o1, ListNode o2) {
               return o1.val-o2.val;
           }
       });
       for(int i=0;i<lists.length;i++){
           queue.add(lists[i]);
       }
       ListNode res = new ListNode(-1);
       ListNode cur =res;
       while(!queue.isEmpty()){
           ListNode next_node = queue.poll();
           if(next_node.next!=null){
                   queue.add(next_node.next);
           }
           cur.next = next_node;
           cur=next_node;
       }

       return res.next;
   }
}

时间复杂度:O(nlogn)

空间复杂度:O(n)

@joriscai
Copy link

joriscai commented Dec 5, 2021

思路

  • 自定义堆,将链头最小的放在顶部,实现小顶堆

代码

javascript

/*
 * @lc app=leetcode.cn id=23 lang=javascript
 *
 * [23] 合并K个升序链表
 */

// @lc code=start
/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode[]} lists
 * @return {ListNode}
 */
var mergeKLists = function (lists) {
  const heap = new minHeap()
  const dummyHead = new ListNode()
  let cur = dummyHead
  for (const list of lists) {
    if (!list) continue
    heap.enqueue(list, list.val)
  }

  while (!heap.isEmpty()) {
    let node = heap.dequeue()
    cur.next = node
    cur = cur.next
    node.next && heap.enqueue(node.next, node.next.val)
  }

  return dummyHead.next
};

// @lc code=end

复杂度分析

  • 时间复杂度:O(k * nlogk), n 是链表的节点数,k 是链表个数。
  • 空间复杂度:O(k)

@wangwiitao
Copy link

var mergeKLists = function (lists) {
    const list = [];
    for (let i = 0; i < lists.length; i++) {
        let node = lists[i];
        while (node) {
            list.push(node.val);
            node = node.next;
        }
    }
    list.sort((a, b) => a - b);
    const res = new ListNode();
    let now = res;
    for (let i = 0; i < list.length; i++) {
        now.next = new ListNode(list[i]);
        now = now.next;
    }
    return res.next;
};

@xinhaoyi
Copy link

xinhaoyi commented Dec 5, 2021

class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length == 0) //特判
return null;
//优先队列,按照值从小到大排序
PriorityQueue queue = new PriorityQueue<>((o1, o2) -> o1.val - o2.val);
//排序后的链表的头节点
ListNode newHead = new ListNode(-1);
ListNode l1 = newHead;
//将链表数组中每个链表加入队列中
for (ListNode i : lists)
if (i != null)
queue.add(i);
while (!queue.isEmpty()) {
//将链表数组中最小的值的那整个链表弹出
l1.next = queue.poll();
//遍历下一个节点
l1 = l1.next;
//如果该链表不为空
if (l1.next != null)
//将该链表下一个值加入队列
queue.add(l1.next);
}
return newHead.next;
}
}

@for123s
Copy link

for123s commented Dec 5, 2021

代码

  • 语言支持:C++

C++ Code:

class Solution {
public:

    ListNode* merge2Lists(ListNode* l, ListNode* r)
    {
        if(!l)
            return r;
        if(!r)
            return l;
        ListNode* idx = new ListNode();
        ListNode* head = idx;
        while(l&&r)
        {
            if(l->val<r->val)
            {
                idx->next = l;
                l = l->next;
            }
            else
            {
                idx->next = r;
                r = r->next;
            }
            idx = idx->next;
            idx->next = nullptr;
        }
        while(l)
        {
            idx->next = l;
            l = l->next;
            idx = idx->next;
            idx->next = nullptr;
        }
        while(r)
        {
            idx->next = r;
            r = r->next;
            idx = idx->next;
            idx->next = nullptr;
        }
        return head->next;
    }

    ListNode* merge(vector<ListNode*>& lists,int l,int r)
    {
        if(l==r)
            return lists[l];
        if(l>r)
            return nullptr;
        int mid = (l+r)>>1;
        return merge2Lists(merge(lists, l, mid), merge(lists, mid + 1, r));
    }

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        return merge(lists,0,lists.size()-1);
    }
};

@taojin1992
Copy link

k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i] is sorted in ascending order.
The sum of lists[i].length won't exceed 10^4.

[]
[[]]

pq keeps all the heads, minheap, poll the element and insert its next
done, when it is empty (note: do not insert null)

## Time:
num of lists = k, average len of each list = m
O(k * logk) +  O(mk * logk)

## Space:
priorityQueue, O(k)
final list O(k * m)

Code:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        ListNode dummy = new ListNode(0);
        ListNode cur = dummy;
        PriorityQueue<ListNode> minHeap = new PriorityQueue<>((a, b)->(a.val - b.val));
        for (ListNode list : lists) {
            if (list != null) {
                minHeap.add(list);
            }
        }
        while (!minHeap.isEmpty()) {
            ListNode curNode = minHeap.poll();
            cur.next = curNode;
            cur = cur.next;
            
            if (curNode.next != null) {
                minHeap.offer(curNode.next);
            }
        }
        return dummy.next;
    }
}

@A-PolarBear
Copy link

class Solution {

    public ListNode mergeKLists(ListNode[] lists) {

        if (lists == null || lists.length == 0)
            return null;

        ListNode res = null;

        for (int i = 0; i < lists.length; i++)
            res = mergeTwoLists(res, lists[i]);

        return res;
    }

    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {

        if (l1 == null || l2 == null)
            return l1 == null ? l2 : l1;

        ListNode fakehead = new ListNode(0), tmp = fakehead;

        while (l1 != null && l2 != null) {

            if (l1.val < l2.val) {

                fakehead.next = l1;
                l1 = l1.next;
            } else {

                fakehead.next = l2;
                l2 = l2.next;
            }

            fakehead = fakehead.next;
        }

        fakehead.next = l1 != null ? l1 : l2;
        return tmp.next;
    }
}

@Richard-LYF
Copy link

class Solution {

public ListNode mergeKLists(ListNode[] lists) {

    PriorityQueue<ListNode> queue = new PriorityQueue<>((l1, l2) -> l1.val - l2.val);
    ListNode fakeHead = new ListNode(0);
    ListNode temp = fakeHead;

    for (ListNode head: lists)
        if (head != null)
            queue.offer(head);

    while (!queue.isEmpty()) {

        ListNode curr = queue.poll();

        if (curr.next != null)
            queue.offer(curr.next);

        temp.next = curr;
        temp = temp.next;
    }
    return fakeHead.next;
}

}

@machuangmr
Copy link

代码

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
     if(lists.length == 0) {
         return null;
     }
     return merge(lists, 0, lists.length - 1);
    }

    public ListNode merge (ListNode[] lists, int lo, int high) {
        if(lo == high) {
            return lists[lo];
        }

        int mid = lo + (high - lo) / 2;
        ListNode l1 = merge(lists, lo, mid);
        ListNode l2 = merge(lists, mid + 1, high);
        return merge2Lists(l1, l2);
    }

    public ListNode merge2Lists(ListNode l1, ListNode l2) {
        if(l1 == null) {
            return l2;
        }
        if(l2 == null) {
            return l1;
        }

        ListNode newList = null;
        if(l1.val < l2.val){
            newList = l1;
            newList.next = merge2Lists(l1.next, l2);
        } else {
            newList = l2;
            newList.next = merge2Lists(l1, l2.next);
        }
        return newList;
    }
}

@revisegoal
Copy link

Note

优先队列,小顶堆

Code

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }
        ListNode cur = lists[0];
        ListNode pre = new ListNode(0, cur);// 哑节点
        int n = lists.length;
        PriorityQueue<ListNode> queue = 
        new PriorityQueue<>((a, b) -> ((ListNode)a).val - ((ListNode)b).val); 
       

        if (cur == null) {
            boolean empty = true;
            for(int i = 1; i < n; i++) {
                if (lists[i] != null) {
                    lists[0] = cur = lists[i];
                    lists[i] = null;
                    empty = false;
                    break;
                }
            }
            if (empty) {
                return null;
            }
        }
      
        ListNode ans = lists[0];
        while (cur != null) {
            for (int i = 1; i < n; i++) {
                while (lists[i] != null && lists[i].val <= cur.val) {
                    queue.add(lists[i]);
                    lists[i] = lists[i].next;
                }
            }
            if (cur == lists[0] && queue.size() != 0) {
                ans = queue.peek();
            }
            while (queue.size() != 0) {
                ListNode add = queue.remove();
                pre.next = add;
                add.next = cur;
                pre = add;
            }
            pre = cur;
            cur = cur.next;
        }
        
        for (int i = 1; i < n; i++) {
            while (lists[i] != null) {
                queue.add(lists[i]);
                lists[i] = lists[i].next;
            }
        }
        while (queue.size() != 0) {
                ListNode add = queue.remove();
                pre.next = add;
                add.next = cur;
                pre = add;
        }

        return ans;
    }
}

Complexity

  • time:O(nlogn)
  • space:O(n)

@yingliucreates
Copy link

link:

https://leetcode.com/problems/merge-k-sorted-lists/

代码 Javascript

function merge(left, right) {
  if (!left) {
    return right;
  } else if (!right) {
    return left;
  } else if (left.val < right.val) {
    left.next = merge(left.next, right);
    return left;
  } else {
    right.next = merge(left, right.next);
    return right;
  }
}

function helper(lists, start, end) {
  if (start === end) {
    return lists[start];
  } else if (start < end) {
    const mid = parseInt((start + end) / 2);
    const left = helper(lists, start, mid);
    const right = helper(lists, mid + 1, end);
    return merge(left, right);
  } else {
    return null;
  }
}

const mergeKLists = function (lists) {
  return helper(lists, 0, lists.length - 1);
};

@hellowxwworld
Copy link

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        if (lists.empty())
            return nullptr;

        ListNode* res;
        auto cmp = [](ListNode* n1, ListNode* n2)
        {
            return n1->val > n2->val;
        };

        /* 使用node的val构造一个小顶堆 */
        priority_queue<ListNode*, vector<ListNode*>, decltype(cmp)> nodesQ(cmp);
        for (auto& list : lists)
        {
            if (list != nullptr)
            {
                nodesQ.push(list);
            }
        }

        ListNode* fakeHead = new ListNode(-1);  /* 创建虚拟头结点 */
        ListNode* cur = fakeHead;
        while (!nodesQ.empty()) 
        {
            cur->next = nodesQ.top();  /* 取出最小值对应的结点指针,挂接在游标指针上 */
            cur = cur->next;
            nodesQ.pop();

            if (cur->next != nullptr)  /* 只要挂接点后面还有结点,则将其压入栈,继续从中拿出最小值,循环往复 */
            {
                nodesQ.push(cur->next);
            }
        }
        return fakeHead->next;
    }
};```

@pophy
Copy link

pophy commented Dec 7, 2021

思路1 - PQ

  • 把第一列的每个数坐标放入PQ
  • 弹出PQ中的最小值 cur 放入list,如果cur右边的数不越界 把cur右边的数放入PQ
  • 当list.size == k时 返回list中最后一个值

Java Code

    public int kthSmallest(int[][] matrix, int k) {
        int n = matrix.length;
        List<Integer> countList = new ArrayList<>();
        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> matrix[a[0]][a[1]]));
        for (int i = 0; i < n; i++) {
            pq.add(new int[]{i, 0});
        }
        while (countList.size() != k) {
            int[] cur = pq.poll();
            int x = cur[0], y = cur[1];
            countList.add(matrix[x][y]);
            if (y + 1 < n) {
                pq.add(new int[]{x, y + 1});
            }
        }
        return countList.get(k - 1);
    }

思路2 - 二分搜值

  • 二分猜第K个数的大小值m : m = (l + r) / 2
    • 统计数组中小于等于m的数, 记为count
    • 如果count > k,说明m偏大 收缩右边界
    • 否则m偏小 收缩左边界

Java Code

class Solution {
    public int kthSmallest(int[][] matrix, int k) {
        int n = matrix.length;
        int l = matrix[0][0], r = matrix[n - 1][n - 1];
        while (l <= r) {
            int m = l + (r - l) / 2;
            if (count(matrix, m) < k) {
                l = m + 1;
            } else {
                r = m - 1;
            }
        }
        if (count(matrix, r) == k) {
            return r;
        } else {
            return l;
        }
    }
    private int count(int[][] matrix, int key) {
        int n = matrix.length;
        int x = n - 1, y = 0, count = 0;
        while (x >= 0 && y < n) {
            if (matrix[x][y] > key) {
                x--;
            } else {
                count += x + 1;
                y++;
            }
        }
        return count;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests