题目:合并 k 个排序链表,返回合并后的排序链表。
eg:输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
答案:
方法一:将所有元素放进一个数组中,将数组排序后,返回一个新的链表
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
ListNode Head = new ListNode(0);
ListNode p = Head;
int n=0,i=0;
for(ListNode l:lists){ //计算总长度
while(l!=null){
l = l.next;
n++;
}
}
int[] myList = new int[n];
for(ListNode l:lists){ //将所有元素放入数组中
while(l!=null){
myList[i] = l.val;
l = l.next;
i++;
}
}
Arrays.sort(myList); //排序
for(int x:myList){ //建立新的链表
p.next = new ListNode(x);
p = p.next;
}
return Head.next;
}
}
方法二:
使用优先队列PriorityQueue。
Java中PriorityQueue通过二叉小顶堆实现。优先队列的作用是能保证每次取出的元素都是队列中权值最小的
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length == 0) {
return null;
}
PriorityQueue<Integer> queue = new PriorityQueue<>();
for (ListNode node : lists) { //将所有元素插入优先队列
while (node != null) {
queue.offer(node.val);
node = node.next;
}
}
return getNode(queue);
}
private ListNode getNode(PriorityQueue<Integer> queue) {
if (!queue.isEmpty()) {
ListNode node = new ListNode(queue.poll()); //poll():移除并返问队列头部(删除前)的元素
node.next = getNode(queue);
return node;
}
return null;
}
方法三:
以合并两个有序链表为基础,进行多个链表的合并
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
return merge(lists, 0, lists.length - 1);
}
public ListNode merge(ListNode[] lists, int i, int j) {
if(j < i) return null;
if(i == j) return lists[i];
if(j > i + 1) {
return baseMerge(merge(lists, i, (i+j)/2), merge(lists, ((i+j)/2)+1, j)); //融合分而治之
}
ListNode l1 = lists[i];// i+1=j时
ListNode l2 = lists[j];
return baseMerge(l1,l2);
}
public ListNode baseMerge(ListNode l1, ListNode l2) { //合并两个链表
if(l1 == null) return l2;
if(l2 == null) return l1;
ListNode start = l1.val < l2.val ? l1 : l2;
ListNode nonStart = l1.val < l2.val ? l2 : l1;
start.next = baseMerge(start.next,nonStart);
return start;
}
}
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length < 1)
return null;
ListNode node = merge(lists,0,lists.length - 1);
return node;
}
public ListNode merge(ListNode[] lists, int L, int R){
if(L == R)
return lists[L];
int mid = L + ((R-L) >> 1);
ListNode node1 = merge(lists,L,mid); //合并左半部分列表
ListNode node2 = merge(lists,mid+1,R);//合并右半部分列表
ListNode node = mergeTwoList(node1,node2);//合并两段已经合并好的列表
return node;
}
private ListNode mergeTwoList(ListNode l1, ListNode l2){ //合并两个列表
if(l1 == null) return l2;
if(l2 == null) return l1;
ListNode node;
if(l1.val < l2.val){
node = new ListNode(l1.val);
node.next = mergeTwoList(l1.next,l2);
} else {
node = new ListNode(l2.val);
node.next = mergeTwoList(l1,l2.next);
}
return node;
}
}
需要注意的地方:
- 数组必须提前定义长度
- 充分运用递归的思想
- 学会将问题分解
- PriorityQueue的使用