合并k个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
方法一
思路
先把节点放进数组 再对数组进行排序,最后再拼接成链表。 这里如果节点放入的是小顶堆而不是数组的话,可以省掉排序,时间复杂度是(nlogk)
时间复杂度O(nlogn) 空间复杂度O(n)
func mergeKLists1(_ lists: [ListNode?]) -> ListNode? {
if lists.isEmpty || lists.count == 0 {
return nil
}
var nodes = [ListNode]()
for list in lists {
var temp = list
while temp != nil {
nodes.append(temp!)
temp = temp?.next
}
}
///这里排序比较 时间复杂度最好的是O(nlogn)
nodes.sort { (l1, l2) -> Bool in
return (l1.val - l2.val) < 0 ? true : false
}
let head = ListNode(-1)
var cur = head
for node in nodes {
cur.next = node
cur = node
}
return head.next
}
方法二
思路
逐一比较 时间复杂度 O(kn) k为链表数
依次从头节点中找到最小的节点,拼接到新链表 同时头节点后移
func mergeKLists2(_ lists: [ListNode?]) -> ListNode? {
if lists.isEmpty || lists.count == 0 {
return nil
}
var lists = lists
let head = ListNode(-1)
var cur = head
while true {
var minIndex = -1
for (i,node) in lists.enumerated() {
guard let node = node else { continue }
if minIndex == -1 || node.val < lists[minIndex]!.val {
minIndex = i
}
}
if minIndex == -1 {
break
}
cur.next = lists[minIndex]
cur = cur.next ?? ListNode(-1)
lists[minIndex] = lists[minIndex]?.next
}
return head.next
}
方法三
思路
逐一两两合并 时间复杂度 O(kn) k为链表数
需要依赖合并2个有序链表的方法,可以看上一篇文章
func mergeKLists3(_ lists: [ListNode?]) -> ListNode? {
if lists.isEmpty || lists.count == 0 {
return nil
}
var lists = lists
for i in 1..<lists.count {
lists[0] = mergeTwoLists(lists[0], lists[i])
}
return lists[0]
}
方法四
思路
分治 时间复杂度(nlogk)
把相近的链表两两合并,直到合并完成
func mergeKLists4(_ lists: [ListNode?]) -> ListNode? {
if lists.isEmpty || lists.count == 0 {
return nil
}
var lists = lists
var step = 1
while step < lists.count {
let nextStep = step << 1
for i in stride(from: 0, to: lists.count - step, by: nextStep) {
lists[i] = mergeTwoLists(lists[i], lists[i+step])
}
step = nextStep
}
return lists[0]
}