目录
- 题目
- 分析
- 顺序合并
- 最优解分治合并
- 总结
题目
分析
首先你要会写合并两个有序链表,这个题目就是合并两个链表的变形,如果懂合并两个,那么合并k个也就不难了,只要弄一个遍历即可,一开始最前面两个合并,将合并的结果与第一个合并,以此类推,每次都进行两个两个合并,知道和最后一个合并完毕,思路都不难
顺序合并
import java.util.*;
public class Solution {
public ListNode mergeKLists(ArrayList<ListNode> lists) {
//思路:k个有序链表合并,就是进行多次两个有序链表的合并
//首先若k=0,即为空,则直接返回null
if(lists == null || lists.size() == 0){
return null;
}
//若k=1,则直接返回这个链表,无需要排序
if(lists.size() == 1){
return lists.get(0);
}
//若k>1,则执行合并,先前两个合并,将合并后的结果再和后面的链表合并
//遍历合并
ListNode node = lists.get(0);
for(int i = 1 ; i < lists.size() ; i++){
node = mergeTwoList(node,lists.get(i));
}
return node;
}
private ListNode mergeTwoList(ListNode node1,ListNode node2){
ListNode temp = new ListNode(-1);//头结点,记录两个合并的链表
ListNode node = temp;//记录这个头结点,后面用于返回合并后的第一个节点node.next
while(node1 != null && node2 != null){
//小的先连到temp的后面
if(node1.val < node2.val){
temp.next = node1;
node1 = node1.next;
}else{
temp.next = node2;
node2 = node2.next;
}
temp = temp.next;
}
//若node1或者node2没有执行完,则直接连接到temp后面
if(node1 != null){
temp.next = node1;
}
if(node2 != null){
temp.next = node2;
}
//返回合并后的第一个节点
return node.next;
}
}
下面是LeetCode,顺序合并
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
//合并k个有序链表就是合并两个有序链表的升级,只要遍历lists,两个两个合并即可
ListNode res = null;
int len = lists.length;
for(int i = 0 ; i < len ; i++){
res = mergeTwoList(res,lists[i]);
}
return res;
}
private ListNode mergeTwoList(ListNode l1, ListNode l2){
//处理初始传递过程中存在的null
if(l1 == null || l2 == null){
return l1 == null ? l2 : l1;
}
//l1和l2均!=null,进行合并
//创建一个头节点
ListNode head = new ListNode(-1);
ListNode cur = head;
while(l1 != null && l2 != null){
if(l1.val <= l2.val){
cur.next = l1;
cur = cur.next;
l1 = l1.next;
}else{
cur.next = l2;
cur = cur.next;
l2 = l2.next;
}
}
if(l1 != null){
cur.next = l1;
}
if(l2 != null){
cur.next = l2;
}
return head.next;
}
}
最优解分治合并
先分,然后再归并
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists == null || lists.length == 0){
return null;
}
//分治合并
return merge(lists,0,lists.length - 1);
}
private ListNode merge(ListNode[] lists,int left,int right){
//分治返回合并的结点
if(left == right) return lists[left];
//left != right
int mid = (left + right) / 2;
ListNode l1 = merge(lists,left,mid);//合并左半边
ListNode l2 = merge(lists,mid+1,right);//合并右半边
return mergeTwoLists(l1,l2);
}
//两两合并
private ListNode mergeTwoLists(ListNode l1, ListNode l2){
//处理初始传递过程中存在的null
if(l1 == null || l2 == null){
return l1 == null ? l2 : l1;
}
//l1和l2均!=null,进行合并
//创建一个头节点
ListNode head = new ListNode(-1);
ListNode cur = head;
while(l1 != null && l2 != null){
if(l1.val <= l2.val){
cur.next = l1;
cur = cur.next;
l1 = l1.next;
}else{
cur.next = l2;
cur = cur.next;
l2 = l2.next;
}
}
if(l1 != null){
cur.next = l1;
}
if(l2 != null){
cur.next = l2;
}
return head.next;
}
}
总结
当数据量大时,顺序合并和归并合并,速度基本不在一个量级,一个100ms+,一个1ms,所以我们这里用归并