天机阁

23. 合并K个升序链表

2022-07-04 · 3 min read
LeetCode

题目

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

难度:🌟🌟🌟🌟🌟

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

示例 2:

输入:lists = []
输出:[]

示例 3:

输入:lists = [[]]
输出:[]

提示:

  • k == lists.length
  • 0 <= k <= 104
  • 0 <= lists[i].length <= 500
  • -104 <= lists[i][j] <= 104
  • lists[i] 按 升序 排列
  • lists[i].length 的总和不超过 104

题解

思路一:
K个升序链表合并,可以先把第0条和第1条合并,合并产生一条新链表l,再将新链表l和第2条链表合并,依此循环,直到和K个升序链表合并完毕。

思路二:

如图所示,通过分治的方法合并链表。

  • 将 k 个链表配对并将同一对中的链表合并;
  • 第一轮合并以后, k 个链表被合并成了 k2\frac{k}{2} 个链表,平均长度为 2nk\frac{2n}{k} ,然后是 k4\frac{k}{4} 个链表, k8\frac{k}{8} 个链表等等;
  • 重复这一过程,直到我们得到了最终的有序链表。

代码实现

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */

// 思路一:循环合并
func mergeKLists(lists []*ListNode) *ListNode {
	var p *ListNode
	for i := 0; i < len(lists); i++ {
		p = mergeTwoList(p, lists[i])
	}
	return p
}

// 思路二:分治合并
func mergeKLists(lists []*ListNode) *ListNode {
	return merge(lists, 0, len(lists)-1)
}

func merge(lists []*ListNode, left, right int) *ListNode {
	if left == right {
		return lists[left]
	}
	if left > right {
		return nil
	}
	mid := left + (right-left)/2
	p1 := merge(lists, 0, mid)
	p2 := merge(lists, mid+1, right)
	return mergeTwoList(p1, p2)
}

// mergeTwoList 合并两个链表
func mergeTwoList(list1, list2 *ListNode) *ListNode {
	dummy := &ListNode{Val: -1}
    p := dummy
	p1, p2 := list1, list2
	for p1 != nil && p2 != nil {
		val := 0
		if p1.Val < p2.Val {
			val = p1.Val
			p1 = p1.Next
		} else {
			val = p2.Val
			p2 = p2.Next
		}
		p.Next = &ListNode{Val: val}
		p = p.Next
	}
	if p1 != nil {
		p.Next = p1
	}
	if p2 != nil {
		p.Next = p2
	}
	return dummy.Next
}