Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
11/3 这道题也跟狗家的onsite有点像, 下面讲讲俺的思路:
之前的解法:
把这些lists两两merge, 知道最后只剩下一个list
public class Solution {
public ListNode mergeKLists(List<ListNode> lists) {
/*CAUTION: use a loop to remove throws an error
http://stackoverflow.com/questions/8189466/java-util-concurrentmodificationexception
*/
//if(lists.size() > 300) return null;
List<ListNode> remove = new ArrayList<ListNode>();
for(int i= lists.size()-1; i>=0; i--){
if(lists.get(i) == null){
lists.remove(i);
}
}
ListNode tail = null, list = null;
while( !lists.isEmpty() ){
ListNode p = lists.get(0);
ArrayList<Integer> rm = new ArrayList<Integer>();
for(int i=0; i<lists.size(); i++){
ListNode node = lists.get(i);
if(node.val < p.val){
p = node;
}
}
for(int i=lists.size()-1; i>=0; i--){
if(lists.get(i).val == p.val){
rm.add(Integer.valueOf(i));
}
}
for(int j=0; j<rm.size(); j++){
int index = rm.get(j).intValue();
ListNode q = lists.get(index);
if(list == null){
list = q;
}else{
tail.next = q;
}
tail = q;
q = q.next;
if(q == null){
lists.remove(index);
}else{
lists.remove(index);
lists.add(q);
}
}
}
return list;
}
}
空间复杂度是O(1),
时间复杂度:
首先假设list 2i 和 list 2i+1 合并成list i, 时间是O(m), m是最长的一个list的长度, 一共有n/2个要合并, 假设没有空的list
然后是list 2i和list 2i+2 合并成list 2i, 时间是O(2m), 一共是n/4个需要合并
。。。
可以知道对于某一个ListNode, 会被访问lg(n)次, n是list的数量, 所以时间复杂度是O(Nlgn), N是所有node的数量
另一种解法是使用一个heap储存这些lists,每次得到min的时候都需要siftdown,所以时间复杂度是O(Nlgn)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public class Heap{
public ListNode[] list;
public int size = 0;
public Heap(int n){
list = new ListNode[n];
}
public boolean isEmpty(){
return size == 0;
}
public void heapify(){
for(int i=size-1; i>=0; i--){
siftDown(i);
}
}
public ListNode min(){
ListNode head = list[0];
list[0] = list[0].next;
if(list[0] == null){
swap(0,size-1);
size--;
siftDown(0);
}else{
siftDown(0);
}
head.next = null;
return head;
}
private void siftDown(int from){
int left = 2*from + 1;
int right = left + 1;
if(left >= size) return;
int min = from;
if(left < size && list[left].val < list[min].val) min = left;
if(right < size && list[right].val < list[min].val) min = right;
swap(min,from);
if(min != from) siftDown(min);
}
private void swap(int i, int j){
ListNode tmp = list[i];
list[i] = list[j];
list[j] = tmp;
}
}
public ListNode mergeKLists(List<ListNode> lists) {
/**
* try solve with a heap
*/
Heap heap = listToHeap(lists);
if(heap.size == 0) return null;
ListNode ans = heap.min();
ListNode prev = ans;
while(!heap.isEmpty()){
prev.next = heap.min();
prev = prev.next;
}
return ans;
}
public Heap listToHeap(List<ListNode> lists){
int len = lists.size();
Heap heap = new Heap(len);
int start = 0, end = len-1;
for(ListNode list: lists){
if(list != null){
heap.list[start++] = list;
}else{
heap.list[end--] = null;
}
}
heap.size = start;
heap.heapify();
return heap;
}
}