【49.合并K个升序链表】

71 阅读1分钟

题目

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

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

示例 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

题解

方式一:分治

public ListNode mergeKLists(ListNode[] lists) {
    // 也可以遍历K个链表,每次合并i和i+1
    return merge(lists, 0, lists.length - 1);
}

public ListNode merge(ListNode[] lists, int l, int r) {
    if (l > r) {
        return null;
    }
    if (l == r) {
        return lists[l];
    }
    // 利用二分,成对处理链表
    int mid = l + (r - l) / 2;
    return mergeTowLists(merge(lists, l, mid), merge(lists, mid + 1, r));
}

// 原地合并两个升序链表,也可以利用新链表合并
public ListNode mergeTowLists(ListNode p, ListNode q) {
    ListNode dummy = new ListNode();
    ListNode tail = dummy;
    while (p != null && q != null) {
        if (p.val <= q.val) {
            tail.next = p;
            p = p.next;
        } else {
            tail.next = q;
            q = q.next;
        }
        tail = tail.next;
    }
    tail.next = p == null ? q : p;
    return dummy.next;
}

方式二:优先级队列

// 自定义对象实现比较器
class Node implements Comparable<Node> {
    ListNode node;

    Node(ListNode node) {
        this.node = node;
    }

    @Override
    public int compareTo(Node o2) {
        // 升序,保证队列头取到的是最小的
        return this.node.val - o2.node.val;
    }
}

public ListNode mergeKLists(ListNode[] lists) {
    PriorityQueue<Node> queue = new PriorityQueue<>();
    // 把K个链表头节点放入队列
    for (ListNode list: lists) {
        if (list != null) {
            queue.offer(new Node(list));
        }
    }
    ListNode dummy = new ListNode();
    ListNode tail = dummy;
    while (!queue.isEmpty()) {
        // 取出最小的节点
        Node node = queue.poll();
        tail.next = node.node;
        tail = tail.next;
        // 如果没取完,将下一个节点放入队列
        if (node.node.next != null) {
            queue.offer(new Node(node.node.next));
        }
    }
    return dummy.next;
}

总结

算法:分治
数据结构:优先级队列