合併 k 個排序鍊錶,返回合併後的排序鍊錶。請分析和描述演算法的複雜度。
示例:
輸入:
[ 1->4->5,
1->3->4,
2->6
]輸出: 1->1->2->3->4->4->5->6
這裡提供兩個思路,一是不斷通過兩兩合併的方式把全部鍊錶合併起來;二是每次從所有鍊錶中選出最小的那個加到鍊錶尾部。
思路一:這個思路很清晰,但是要注意一點,不能夠一條一條合進來,要進行分治法,先兩兩合併後,再把剩下的兩兩合併。例如1234,先2+1,再3+4,最後再3+7(這裡的1234指的是4個鍊錶)。
思路二:每次從所有節點中抽取乙個節點出來。這裡可以使用乙個優先佇列來維護k個資料。每次從佇列中拿走乙個節點後就把該節點的下一節點放進去。這樣的好處就是,優先佇列可以通過效率比較高的演算法排序(堆演算法),比我們乙個個找的效率要高,壞處就是要占用額外的空間。下面的解答我沒有使用佇列,直接乙個個去查詢,讀者可以自行嘗試。
class
listnode
(var `val`: int)
解答一fun
mergeklists
(lists: array>
): listnode?
if(listarray.
isempty()
)return
null
val listhead =
listnode(0
)var listcurrent = listhead
while
(listarray.
isnotempty()
)}listcurrent.next = listarray[index]
listcurrent = listcurrent.next!!
if(listarray[index]
.next!=
null
) listarray[index]
= listarray[index]
.next!!
else listarray.
removeat
(index)
} listcurrent.next =
null
return listhead.next
}
方法二fun
mergeklists
(lists: array>
): listnode?
funmerge
(lists: array>
,s:int, e:int)
:listnode?
funmergetwolists
(l1: listnode?
, l2: listnode?
): listnode?
val listnode :listnode?
=listnode(0
)var current = listnode
var point1 = l1
var point2 = l2
while
(point1!=
null
&&point2!=
null
)else
current = current?
.next
}if(point1==
null
)else
return listnode?
.next
}
假設一共有k個鍊錶,每個鍊錶的最長長度是n
時間複雜度
第一種方法每次要從k個鍊錶中查詢最小值,一共需要找kn次
第二種方法遞迴的層數是logk,(自底向上)第一層一共分為k/2組,每組需要的時間是o(2n)。第二層一共分為k/4組,每組需要的時間是o(4n),以此類推。
可以看到第二種的速度會更快點,但是如果使用先序佇列,那麼時間複雜度就一樣了。
空件複雜度
第一種方法不需要任何陣列空間,只需要少量變數
第二種方法需要用到遞迴,棧的深度是logk,所以是
合併K個有序鍊錶
public class 023 mergeklists 堆中結點類 author luzhen work pc private static class node implements comparable override public int compareto node o 將k個有序鍊錶歸...
合併k個有序鍊錶
這是leetcode上面的一道程式設計題,題目如下 合併 k 個排序鍊錶,返回合併後的排序鍊錶。請分析和描述演算法的複雜度。示例輸入 1 4 5,1 3 4,2 6 輸出 1 1 2 3 4 4 5 6 利用遞迴分治的思想將k個有序鍊錶的合併問題,分解成多個合併兩個有序鍊錶的問題。比如示例中我們將三...
合併k個有序鍊錶
題幹 合併 k 個排序鍊錶,返回合併後的排序鍊錶。請分析和描述演算法的複雜度。示例 輸入 1 4 5,1 3 4,2 6 輸出 1 1 2 3 4 4 5 6 此題為leetcode中23題。由於此前有合併兩個有序鍊錶的經驗,開始看到這個題,很自然就想到了,每次在k個鍊錶中選取乙個最小的節點鏈結到結...