23. 合并K个排序链表

187 阅读2分钟

leetcode原题链接

合并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]
}