LeetCode第23題,合併k個有序的鏈表.
java
直接遍歷全部鏈表,取出全部節點的值,用數組存儲,非降序排序,而後建立一個新鏈表用頭插法依次插入節點.git
List<Integer> s = new ArrayList<>(); for(ListNode x:lists) { while(x != null) { s.add(x.val); x = x.next; } } s.sort((a,b) -> {return a.compareTo(b);}); ListNode result = new ListNode(0); ListNode t = result; for(Integer x:s) { t.next = new ListNode(x); t = t.next; } return result.next;
這裏要注意一下,sort那裏不能寫成:github
s.sort((a,b)->{return a>b ? 1 : -1;});
沒有考慮到等於的狀況,因此用compareTo代替:數組
s.sort((a,b)->{return a.compareTo(b);});
每次遍歷全部鏈表,取出首節點的值,各個比較而後得出最小值,將最小值插入新鏈表,而後移動最小值所在的鏈表的指針,直到全部鏈表爲空.ide
ListNode result = new ListNode(0); ListNode t = result; int len = lists.length; int nullNodeNums = 0; for(boolean [] b = new boolean[len];nullNodeNums<len;) { int min = Integer.MAX_VALUE; int minIndex = -1; for(int index = 0;index<len;++index) { ListNode x = lists[index]; if(x == null) { if(!b[index]) { b[index] = true; ++nullNodeNums; } } else if(x.val < min) { min = x.val; minIndex = index; } } if(minIndex != -1) { t.next = new ListNode(min); t = t.next; lists[minIndex] = lists[minIndex].next; } } return result.next;
這裏使用了一個布爾數組判斷是否某個節點已經移動到尾部,即表示是否爲空,爲空的話跳過這個節點,不爲空的話取其值,計算是否爲最小值.獲得最小值後,添加到結果節點中,並移動最小值所在鏈表的指針.
這個方法看起來慢得很啊.指針
優先隊列是上兩個方法的結合,遍歷全部節點,取值並根據其值肯定優先級添加到優先隊列中,而後依次出隊,將出隊的值直接插入到新鏈表中.code
PriorityQueue<Integer> queue = new PriorityQueue<>(); for(ListNode x:lists) { while(x != null) { queue.add(x.val); x = x.next; } } ListNode s = new ListNode(0); ListNode t = s; while(!queue.isEmpty()) { t.next = new ListNode(queue.poll()); t = t.next; } return s.next;
java的優先隊列能夠直接add便可,按照默認出隊序列(對於整數是小的先出)使用尾插法插入到新鏈表中.
嗯,好像還能夠的樣子,可是仍是不夠快.blog
合併k個鏈表,至關於合併2個鏈表k-1次,利用遞歸的思想,每次合併兩個鏈表,將合併後的鏈表後返回做爲下一個要合併的鏈表繼續合併.排序
public ListNode mergeKLists(ListNode[] lists) { if (lists == null || lists.length == 0) return null; ListNode t = lists[0]; for(int i=1;i<lists.length;++i) t = merge(t, lists[i]); return t; } //public ListNode merge(ListNode a,ListNode b)
merge爲直接合並兩個鏈表的操做,不難,就不貼代碼了,首先賦值t爲第一個鏈表,而後依次合併t與剩下的n-1個鏈表.
好慢啊.遞歸
分治法是兩兩合併法的改進,兩兩合併每次合併兩個鏈表,分治法每次合併一半數量的鏈表,整體思想是這樣的:想要獲得最終有序的鏈表,若左半部分的鏈表與右半部分的鏈表都有序,則至關於合併兩個有序鏈表,爲了獲得左半部分的有序鏈表,須要繼續對左半部分進行一半的分割,再次分紅左半部分與右半部分,而後再分,直到某部分只有一個鏈表,而後返回,以合併兩個普通有序鏈表的方式合併兩個返回的鏈表.
public ListNode f(int start,int end) { int len = end - start; if(len <= 1) return lists[start]; ListNode l = f(start,start+len/2); ListNode r = f(start+len/2,end); return merge(l, r); }
代碼很是簡潔,一開始爲判斷遞歸的條件,區間長度小於等於1直接返回[start]的節點,而後遞歸合併左半部分與右半部分的節點.
一個字,舒服.
真快.