给你一个链表数组,每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中,返回合并后的链表,原题:https://leetcode.com/problems/merge-k-sorted-lists/
我们利用Java自带的PriorityQueue,这个queue底层实现实际上是通过数组实现的小根堆(小顶堆,名字无所谓怎么叫啦),反正就是加进去的数据可以自动排序,所以我们可以利用所有有自动排序的功能的集合来实现这个功能,只是队列用起来方便一点,像treeset等有序集合要一边加一边删有点麻烦,至于说能不能用java自带的这些工具,这个题目的重点不是让你实现排序,所以我觉得是可以的,当然要自己实现一个排序的集合,其实也不难
解题思路:
废话不多说,直接上代码:
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;
}