合并K个升序链表

给你一个链表数组,每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中,返回合并后的链表,原题:https://leetcode.com/problems/merge-k-sorted-lists/

我们利用Java自带的PriorityQueue,这个queue底层实现实际上是通过数组实现的小根堆(小顶堆,名字无所谓怎么叫啦),反正就是加进去的数据可以自动排序,所以我们可以利用所有有自动排序的功能的集合来实现这个功能,只是队列用起来方便一点,像treeset等有序集合要一边加一边删有点麻烦,至于说能不能用java自带的这些工具,这个题目的重点不是让你实现排序,所以我觉得是可以的,当然要自己实现一个排序的集合,其实也不难

解题思路:

  1. 先把每个有序链表的头结点放到PriorityQueue里面去,这样队列第一个元素就是那个最小的头结点
  2. 从队列取出第一个元素,作为最终要返回的链表的头结点head,同时我们定义一个移动的指针pointer
  3. 只要队列不为空,每次从队列取出第一个元素cur之后,将pointer的next指向cur,再将pointer指向cur,同时如果取出的cur的next不为空,就把cur的next添加到队列里头去

废话不多说,直接上代码:

public class SortArrayMerge {
    public static void main(String[] args) {
        ListNode one = new ListNode(1, new ListNode(3, new ListNode(5)));
        ListNode two = new ListNode(2, new ListNode(4, new ListNode(6)));
        ListNode three = new ListNode(3, new ListNode(5, new ListNode(7)));
        ListNode[] listNodes = new ListNode[]{one, two, three};
        ListNode head = sortArrayMerge(listNodes);
        System.err.println(head.val);
        while (head.next != null) {
            System.err.println(head.next.val);
            head = head.next;
        }
    }

    public static ListNode mergeKLists(ListNode[] listNodes) {
        PriorityQueue priorityQueue = new PriorityQueue<>((o1, o2) -> {
            return o1.val - o2.val;
        });
        if (listNodes != null) {
            for (ListNode listNode : listNodes) {
                if (listNode != null) {
                    priorityQueue.add(listNode);
                }
            }
            ListNode head = priorityQueue.poll();
            if (head != null && head.next != null) {
                priorityQueue.add(head.next);
            }
            ListNode pointer = head;
            while (!priorityQueue.isEmpty()) {
                ListNode cur = priorityQueue.poll();
                pointer.next = cur;
                if (cur.next != null) {
                    priorityQueue.add(cur.next);
                }
                pointer = cur;
            }
            return head;
        }
        return null;
    }

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

        public ListNode() {
        }

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

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

        public int getVal() {
            return val;
        }

        public void setVal(int val) {
            this.val = val;
        }

        public ListNode getNext() {
            return next;
        }

        public void setNext(ListNode next) {
            this.next = next;
        }
    }
}

基于优先级队列还有一种思路:就是预先把所有的数据都丢到队列里头去,然后再挨个去从队列里面取。但是这种思路无法解决不了循环引用,而且如果链表数据过多的话可能会很耗内存:

 public static ListNode mergeKLists(ListNode[] listNodes) {
        PriorityQueue priorityQueue = new PriorityQueue<>((o1, o2) -> {
            return o1.val - o2.val;
        });
        ListNode pointer = null;
        if (listNodes != null && listNodes.length > 0) {
            for (ListNode listNode : listNodes) {
                if (listNode != null) {
                    priorityQueue.add(listNode);
                    pointer = listNode;
                    while (pointer.next != null) {
                        priorityQueue.add(pointer.next);
                        pointer = pointer.next;
                    }
                }
            }
            ListNode head = priorityQueue.poll();
            pointer = head;
            while (!priorityQueue.isEmpty()) {
                ListNode cur = priorityQueue.poll();
                pointer.next = cur;
                pointer = cur;
            }
            return head;
        }
        return null;
    }

第二种实现方式:用递归的方法,比上面的要难理解一点,我们把所有的链表数组分组,每两个一组进行合并,比如有1234四组链表,我们先将13合并成一个链表A,将24合并成一个链表B,最后再将A和B进行合并

public class SortArrayMergeV2 {
    public static void main(String[] args) {
        ListNode one = new ListNode(1, new ListNode(3, new ListNode(5)));
        ListNode two = new ListNode(2, new ListNode(4, new ListNode(6)));
        ListNode three = new ListNode(3, new ListNode(5, new ListNode(7)));
        ListNode[] listNodes = new ListNode[]{one, two, three};
        ListNode head = mergeKLists(listNodes);
        System.err.println(head.val);
        while (head.next != null) {
            System.err.println(head.next.val);
            head = head.next;
        }
    }

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

    /**
     * 链表数组拆分
     *
     * @param lists
     * @param start
     * @param end
     * @return
     */
    private static ListNode mergeLists(ListNode[] lists, int start, int end) {
        if (start == end) {
            return lists[start];
        }
        int mid = start + (end - start) / 2;//1
        ListNode left = mergeLists(lists, start, mid);//0 1 第一次得到owne和two
        ListNode right = mergeLists(lists, mid + 1, end);//2第一次得到three
        return mergeTwoLists(left, right);
    }

    /**
     * 两链表一组进行合并
     *
     * @param l1
     * @param l2
     * @return
     */
    private static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(0);
        ListNode curr = dummy;
        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                curr.next = l1;
                l1 = l1.next;
            } else {
                curr.next = l2;
                l2 = l2.next;
            }
            curr = curr.next;
        }
        if (l1 != null) {
            curr.next = l1;
        }
        if (l2 != null) {
            curr.next = l2;
        }
        return dummy.next;
    }
}

如果不习惯递归的话,我们也可以采用下面三种方式优化一下,同样还是两个一组进行合并:

    public static ListNode mergeListsV1(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }
        int interval = 1;
        while (interval < lists.length) {
            for (int i = 0; i + interval < lists.length; i += interval * 2) {
                lists[i] = mergeTwoLists(lists[i], lists[i + interval]);
            }
            interval *= 2;
        }
        return lists[0];
    }
    private static ListNode mergeListsV2(ListNode[] lists) {
        int length = lists.length;
        ListNode newHead = null;
        int left = 0;
        int right = length - 1;
        if (lists != null && lists.length > 0) {
            while (left <= right) {
                if (left == right) {
                    newHead = mergeTwoLists(newHead, lists[left]);
                } else {
                    newHead = mergeTwoLists(mergeTwoLists(lists[left], lists[right]), newHead);
                }
                right--;
                left++;
            }
        }
        return newHead;
    }
    private static ListNode mergeListsV3(ListNode[] lists) {
        int length = lists.length;
        ListNode newHead = null;
        if (lists != null && lists.length > 0) {
            for (int i = 0, j = length - 1; i <= length / 2 && i <= j; i++, j--) {
                if (i == j) {
                    newHead = mergeTwoLists(newHead, lists[i]);
                } else {
                    newHead = mergeTwoLists(mergeTwoLists(lists[i], lists[j]), newHead);
                }
            }
        }
        return newHead;
    }

你可能感兴趣的:(算法积累,链表,redis,数据结构)