合併 k 個排序鍊錶,返回合併後的排序鍊錶。請分析和描述演算法的複雜度。
示例:
輸入:[1
->4-
>5,
1->3-
>4,
2->6]
輸出:1
->1-
>2-
>3-
>4-
>4-
>5-
>
6
方法一:貪心演算法、優先序列思路分析:
1、由於是 k個排序鍊錶,那麼這 k 個排序的煉表頭結點中 val 最小的結點就是合併以後的鍊錶中最小的結點
2、最小結點所在的鍊錶的頭結點就要更新了,更新成最小結點的下乙個結點(如果有的話),此時還是這 k 個鍊錶,這 k 個排序的煉表頭結點中 val 最小的結點就是合併以後的鍊錶中第 2 小的結點
/**
* definition for singly-linked list.
* public class listnode
* }*/public
class
solution
priorityqueue
priorityqueue =
newpriorityqueue
<
>
(len, comparator.
comparingint
(a -
> a.val));
listnode dummynode =
newlistnode(-
1); listnode curnode = dummynode;
for(listnode list : lists)
}while
(!priorityqueue.
isempty()
)}return dummynode.next;
}}
執行結果:
複雜度分析:
時間複雜度:o(n*logk),這裡 n 是這 k 個鍊錶的結點總數,每一次從乙個優先佇列中選出乙個最小結點的時間複雜度是 o(logk)),故時間複雜度為 o(n*logk)
空間複雜度:o(k),使用優先佇列需要 k 個空間,「穿針引線」需要常數個空間,因此空間複雜度為 o(k)
方法二:分治法思路分析:
1、先一分為二,分別「遞迴地」解決了與原問題同結構,但規模更小的兩個子問題;
2、再考慮如何合併,這個合併的過程也是乙個遞迴方法
/**
* definition for singly-linked list.
* public class listnode
* }*/class
solution
//處理奇數的情況。把最後乙個鍊錶放到下次待求解陣列的末端,順便解決向上取整的問題if(
(len%2)
!=0)//規模減半
len/=2;
}return lists[0]
;}public listnode mergetwolists
(listnode l1,listnode l2)
if(l2==null)
if(l1.val
else
prev = prev.next;
}return head.next;
}}
執行結果:
複雜度分析:
時間複雜度:o(n*logk),這裡 n 是這 k 個鍊錶的結點總數,k 個鍊錶二分是對數級別的。
空間複雜度:o(n)
不積跬步無以至千里,不積細流無以成江海
方法一運用了貪心策略,或者說是優先佇列,每次比較k個鍊錶的首結點,取其中最小的結點
方法二運用了分治法,也可以叫二分法,將k個鍊錶進行逐步二分,對其中最小的二分單元進行兩個鍊錶的合併,是之前所練習過的內容
這道題目還有很多其他的解法,充分反映出演算法的多樣性,也體現了不同演算法對不同題目的適應性是不一樣的,在不同的問題之中,最適合的演算法也是不一樣的
所有對於程式設計人員而言,需要勤思考,多實踐,一步一步慢慢積累優秀的演算法,以此達到在實際操作的過程之中可以觸類旁通,靈活運用
合併k個排序鍊錶
合併k個排序鍊錶,並且返回合併後的排序鍊錶。嘗試分析和描述其複雜度。樣例 給出3個排序鍊錶 2 4 null,null,1 null 返回 1 2 4 null 兩兩合併 合併ab得到c 合併cd得到e definition for listnode.public class listnode pu...
合併K個排序鍊錶
從21.合併兩個有序鍊錶的基礎上,我們已經能夠解決兩個有序鍊錶的問題,現在是k個有序鍊錶,我們可以將第一二個有序鍊錶進行合併,然後將新的有序鍊錶再繼續跟第三個有序鍊錶合併,直到將所有的有序鍊錶合併完成。這樣做思路上是可行的,但是演算法的時間複雜度將會很大,具體就不計算了。有興趣的自己計算下。根據思路...
合併K個排序鍊錶
題目 合併 k 個排序鍊錶,返回合併後的排序鍊錶。請分析和描述演算法的複雜度。示例 輸入 1 4 5,1 3 4,2 6 輸出 1 1 2 3 4 4 5 6 思路 設定乙個堆,每次把每個鍊錶的頭結點放入堆中。記錄每個節點的值與在原陣列中的位置,便於鍊錶往下走。彈出堆中最小值,把最小值所在位置的陣列...