代码重构: leetcode 23. 合并K个升序链表

187 阅读1分钟

23. 合并K个升序链表

  1. 我们可以模仿合并两个链表的那样,扩展到多维,但为了快速比较哪个小,使用优先队列来判断。
  2. 使用归并,两两合并,再最终合并

但需要考虑的点是:如何像合并两个链表那样知道指针移动方向?

实际上是因为本题是链表:当用优先队列pop出元素的时候,元素里面自带移动方向,使用.next指针加入队列即可,但如果不是链表,是数组呢?

可以增加一个临时类:

public class Node{
    int index;//标记数组位置
    int flag;//标记哪个数组
    int value;//标记值
}

每次修改值再加入就行了,如下:

 设数组为nums[][]

 PriorityQueue<Node> pq = new PriorityQueue<>(((o1, o2) -> o1.val-o2.val));
 List<Integer> ans = new ArrayList<>();
 while(!pq.isEmpty()){
     Node cur = pq.poll();
     ans.add(cur.val)
     cur.index++;
     if(cur.index<nums[cur.flag].length){
         cur.val=nums[cur.flag][cur.index];
         pq.offer(cur);
     }
 }

但实际上,当是数组的时候,采用两两归并也是一种很不错的想法,但使用的空间复杂度也不低,操作也比较麻烦,可以考虑上面描述的方法。

回归本题,下面给出使用优先队列的解法:

    public ListNode mergeKLists(ListNode[] lists) {
        ListNode pre = new ListNode(-1);
        ListNode tp = pre;
        PriorityQueue<ListNode> pq = new PriorityQueue<>(((o1, o2) -> o1.val-o2.val));
        for (ListNode list : lists) {
            if (list!=null) pq.offer(list);
        }
        while (!pq.isEmpty()) {
            ListNode cur = pq.poll();
            tp.next = cur;
            if (cur.next != null) pq.offer(cur.next);
            tp = tp.next;
            tp.next = null;
        }
        return pre.next;
    }