【数据结构与算法】合并K个排序链表(Java版)

题干描述

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

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

解法一

让链表两两合并,合并之后的链表再和第三个链表合并。
时间复杂度:k 为链表个数,n 为总的结点数,两两归并,每个结点会被归并 log(k) 次,所以总的时间复杂度为 O(nlog(k)) 。空间复杂度为 O(1)。

public class ListNode {
    public int val;
    public ListNode next;

    public ListNode(int val) {
        this.val = val;
    }

    public ListNode(int val, ListNode next) {
        this.val = val;
        this.next = next;
    }

    public int getData() {
        return val;
    }
}
class Solution {
    public static ListNode mergeKLists(ListNode[] lists) {

        ListNode res = new ListNode(0);  //设置结果
        if (lists == null || lists.length < 0) {
            return null;
        } else if (lists.length == 1) {
            return lists[0];
        } else if (lists.length == 2) {
            mergeTwoLists(lists[0], lists[1]);
        } else {
            res = mergeTwoLists(lists[0], lists[1]);
            for (int i = 2; i < lists.length; i++) {
                mergeTwoLists(res, lists[i]);
            }
        }
        return res;
    }

    public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode res = new ListNode(0);
        ListNode tmp = res;

        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                tmp.next = l1;
                l1 = l1.next;
            } else {
                tmp.next = l2;
                l2 = l2.next;
            }
            tmp = tmp.next;
        }
        //后面是为了补全的,因为链表的长度可能不一样
        if (l1 != null) {
            tmp.next = l1;
        } else {
            tmp.next = l2;
        }
        return res.next;
    }

    public static void main(String[] args) {

        // 前一个节点,指向后一个节点
        ListNode node5 = new ListNode(5, null);
        ListNode node4 = new ListNode(4, node5);
        ListNode node3 = new ListNode(3, node4);
        ListNode node2 = new ListNode(2, node3);
        ListNode node1 = new ListNode(1, node2);

        ListNode node8 = new ListNode(7, null);
        ListNode node7 = new ListNode(5, node8);
        ListNode node6 = new ListNode(3, node7);

        ListNode node11 = new ListNode(6, null);
        ListNode node10 = new ListNode(4, node11);
        ListNode node9 = new ListNode(2, node10);

        ListNode[] lists = new ListNode[3];

        lists[0] = node1;
        lists[1] = node6;
        lists[2] = node9;
        System.out.println(lists);

        ListNode listNode = mergeKLists(lists);

        while (listNode != null) {
            System.out.println(listNode.getData());
            listNode = listNode.next;
        }

    }
}

解法二

用容量为k 的最小堆优先队列,把链表的头结点都放进去,然后出队当前优先队列中最小的,挂上链表,然后让出队的那个节点的下一个入队,再出队当前优先队列中最小的,直到优先队列为空。

借助优先队列(小顶堆)的解法的时间复杂度为O(nlog(k)),k 为链表个数,n 为总的结点数,空间复杂度为O(k),小顶堆需要维护一个长度为k 的数组。

【数据结构与算法】合并K个排序链表(Java版)_第1张图片

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {

        if (lists.length == 0) {
            return null;
        }

        ListNode dummyHead = new ListNode(0);
        ListNode curr = dummyHead;
        PriorityQueue<ListNode> pq = new PriorityQueue<>(new Comparator<ListNode>() {
            @Override
            public int compare(ListNode o1, ListNode o2) {
                return o1.val - o2.val;
            }
        });

        for (ListNode list : lists) {
            if (list == null) {
                continue;
            }
            pq.add(list);
        }

        while (!pq.isEmpty()) {
            ListNode nextNode = pq.poll();
            curr.next = nextNode;
            curr = curr.next;
            if (nextNode.next != null) {
                pq.add(nextNode.next);
            }
        }
        return dummyHead.next;
    }
}

你可能感兴趣的:(数据结构与算法)