https://www.lintcode.com/problem/merge-k-sorted-lists/description
描述
合并k个排序链表,并且返回合并后的排序链表。尝试分析和描述其复杂度。
样例
给出3个排序链表 [2->4->null,null,-1->null],返回 -1->2->4->null
链表结构:
class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
this.next = null;
}
}
方法一:
用 List< ListNode> nodeIs 容器保存当前所有链表的最小元素,比较他们中最小的节点加入所求列表中,该链表指向最小元素的指针后移,直到所有链表的指针都走到尾部。
使用该方法 通过 92% 后超时,设 链表有 n个,链表总长度为 m, 则时间复杂度为:O[n*m],
class Solution {
/**
* @param lists:
* a list of ListNode
* @return: The head of one sorted list.
*/
public ListNode mergeKLists(List<ListNode> lists) {
if(lists==null||lists.size()==0){
return null;
}
List<ListNode> nodeIs=new ArrayList<ListNode>();//存放所有链表指向当前最小元素的指针
for(ListNode node:lists){
if(node==null){//如果这个链表为空,就不分配指针了
continue;
}
nodeIs.add(node);
}
ListNode resultHead=new ListNode(0);//定义所求链表的头指针
ListNode p=resultHead; //需要移动的指针,始终指向链表的尾部
int count=0; //走到头的链表数
int n=nodeIs.size();//需要比较的链表条数
while(count<n){ //如果所有链表都走到头,说明构造结束
ListNode minNode=nodeIs.get(0);//指向最小元素
for(ListNode thisNode:nodeIs){
if(minNode.val>thisNode.val){
minNode=thisNode;
}
}
p.next=new ListNode(minNode.val);
p=p.next;//所求的链表的尾指针后移
nodeIs.remove(minNode); //移除原最小的元素
minNode=minNode.next;
if(minNode==null){
count++;
}else{
nodeIs.add(minNode);//将上一个最小元素,的下一个元素添加到最小指针集合中
}
}
return resultHead.next;
}
}
优化:可将需要比较的各个链表头元素构造成一个堆,这样在建堆之后,每次调整堆 需要的时间复杂度 为 logN,总体时间复杂度会降低为 O[ logN*m]。
class Solution {
/**
* @param lists:
* a list of ListNode
* @return: The head of one sorted list.
*/
public ListNode mergeKLists(List<ListNode> lists) {
if(lists==null||lists.size()==0){
return null;
}
List<ListNode> nodeIs=new ArrayList<ListNode>();//存放所有链表指向当前最小元素的指针
for(ListNode node:lists){
if(node==null){//如果这个链表为空,就不分配指针了
continue;
}
nodeIs.add(node);
}
for(int i=nodeIs.size()-1;i>=0;--i){//从最后一个元素开始,向上调整
adjustDown(nodeIs,i);
}
ListNode resultHead=new ListNode(0);//定义所求链表的头指针
ListNode p=resultHead; //需要移动的指针,始终指向链表的尾部
while(nodeIs.size()>0){
ListNode minNode=nodeIs.get(0);//堆顶元素,肯定为最小元素
ListNode node=new ListNode(minNode.val);
p.next=node;
p=p.next;//p 向后移动
nodeIs.remove(minNode);
minNode=minNode.next;
nodeIs.add(0, minNode);
if(minNode==null){//如果当前链的下个元素为空,直接将堆的最后一个元素移动到堆顶
Collections.swap(nodeIs, 0, nodeIs.size()-1);
nodeIs.remove(nodeIs.size()-1);
}
if(nodeIs.size()>0){
adjustDown(nodeIs, 0);
}
}
return resultHead.next;
}
private void adjustDown(List<ListNode> nodeIs, int i) {//调整为最小堆
int len=nodeIs.size();
while(i<len){
int left=i*2+1,right=i*2+2;
int min_pos=i;
if( (left<len) && (nodeIs.get(left).val < nodeIs.get(min_pos).val)){
min_pos=left;
}
if( (right<len) && (nodeIs.get(right).val < nodeIs.get(min_pos).val)){
min_pos=right;
}
if(min_pos!=i){
Collections.swap(nodeIs, i, min_pos);
i=min_pos;
}else{
break;
}
}
}
}
使用优先队列,实现堆
Queue< ListNode> heap = new PriorityQueue< ListNode>(lists.size(), ListNodeComparator);
public class Solution {
private Comparator<ListNode> ListNodeComparator = new Comparator<ListNode>() {
public int compare(ListNode left, ListNode right) {
return left.val - right.val;
}
};
public ListNode mergeKLists(List<ListNode> lists) {
if (lists == null || lists.size() == 0) {
return null;
}
Queue<ListNode> heap = new PriorityQueue<ListNode>(lists.size(), ListNodeComparator);
for (int i = 0; i < lists.size(); i++) {
if (lists.get(i) != null) {
heap.add(lists.get(i));
}
}
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
while (!heap.isEmpty()) {
ListNode head = heap.poll();
tail.next = head;
tail = head;
if (head.next != null) {
heap.add(head.next);
}
}
return dummy.next;
}
}
方法四:
分治的思想,采用归并排序
public class Solution {
/**
* @param lists: a list of ListNode
* @return: The head of one sorted list.
*/
public ListNode mergeKLists(List<ListNode> lists) {
if (lists.size() == 0) {
return null;
}
return mergeHelper(lists, 0, lists.size() - 1);
}
private ListNode mergeHelper(List<ListNode> lists, int start, int end) {
if (start == end) {
return lists.get(start);
}
int mid = start + (end - start) / 2;
ListNode left = mergeHelper(lists, start, mid);
ListNode right = mergeHelper(lists, mid + 1, end);
return mergeTwoLists(left, right);
}
private ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
while (list1 != null && list2 != null) {
if (list1.val < list2.val) {
tail.next = list1;
tail = list1;
list1 = list1.next;
} else {
tail.next = list2;
tail = list2;
list2 = list2.next;
}
}
if (list1 != null) {
tail.next = list1;
} else {
tail.next = list2;
}
return dummy.next;
}
}