241021-23

64 阅读1分钟

思路

1.首先想到了归并排序的合并操作:


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

        public ListNode[] mergeList(ListNode[] lists) {
            //思路:想到了归并排序分治后两辆合并合并 NlogN
            //还可以扔到大根堆然后
            if (lists.length == 1)
                return lists;
            ArrayList<ListNode> listNodes = new ArrayList<>();
            for (int i = 0; i < lists.length - 1; i = i + 2) {
                ListNode merge = merge(lists[i], lists[i + 1]);
                listNodes.add(merge);
            }
            if(lists.length % 2 > 0)
                listNodes.add(lists[lists.length - 1]);
            return mergeList(listNodes.toArray(new ListNode[listNodes.size()]));
        }

        public ListNode merge(ListNode listNode1, ListNode listNode2) {
            ListNode cur = new ListNode();
            ListNode head = cur;
            while (listNode1 != null && listNode2 != null) {
                if (listNode1.val >= listNode2.val) {
                    cur.next = listNode2;
                    listNode2 = listNode2.next;
                } else {
                    cur.next = listNode1;
                    listNode1 = listNode1.next;
                }
                cur = cur.next;
            }
            if (listNode1 != null && listNode2 == null){
                cur.next = listNode1;
            }
            if (listNode2 != null && listNode1 == null){
                cur.next = listNode2;
            }
            return head.next;
        }
    
}

优化版本的分治

public class Solution {

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

    public ListNode mergeKLists(ListNode[] lists, int left, int right) {
        if (left == right) {
            return lists[left];
        }
        int mid = left + (right - left) / 2;
        ListNode list1 = mergeKLists(lists, left, mid);
        ListNode list2 = mergeKLists(lists, mid + 1, right);
        return mergeTwoSortLinkedList(list1, list2);
    }

     public ListNode mergeTwoSortLinkedList(ListNode listNode1, ListNode listNode2) {
            ListNode cur = new ListNode();
            ListNode head = cur;
            while (listNode1 != null && listNode2 != null) {
                if (listNode1.val >= listNode2.val) {
                    cur.next = listNode2;
                    listNode2 = listNode2.next;
                } else {
                    cur.next = listNode1;
                    listNode1 = listNode1.next;
                }
                cur = cur.next;
            }
            if (listNode1 != null && listNode2 == null){
                cur.next = listNode1;
            }
            if (listNode2 != null && listNode1 == null){
                cur.next = listNode2;
            }
            return head.next;
        }
}

优先队列法

因为链表都有序了,加入头节点构成小根堆,每次出队根节点然后入队next节点,保证堆中始终存在当前最小值

import java.util.Comparator;
import java.util.PriorityQueue;

public class Solution {

    public ListNode mergeKLists(ListNode[] lists) {
        int len = lists.length;
        if (len == 0) {
            return null;
        }

        PriorityQueue<ListNode> minHeap = new PriorityQueue<>(len, Comparator.comparingInt(o -> o.val));
        for (ListNode head : lists) {
            if (head != null) {
                minHeap.offer(head);
            }
        }

        ListNode dummyNode = new ListNode(-1);
        ListNode curNode = dummyNode;
        while (!minHeap.isEmpty()) {
            // 注意:这里我们选择的操作是先从优先队列里拿出最小的元素,然后再添加
            // 事实上,如果优先队列有提供 replace 操作,应该优先选择 replace
            ListNode top = minHeap.poll();
            curNode.next = top;

            curNode = curNode.next;

            if (top.next != null) {
                minHeap.offer(top.next);
            }
        }
        return dummyNode.next;
    }
}