题目描述
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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.length0 <= k <= 10^40 <= lists[i].length <= 500-10^4 <= lists[i][j] <= 10^4lists[i]按 升序 排列lists[i].length的总和不超过10^4
思路 1
使用堆排序,先建好小根堆,将第一轮节点压入堆,弹出最小节点插入新链表中;
如果最小节点还有后续节点,继续压入堆,然后继续弹出;
重复上述操作,直至堆的大小为空位置。
代码
type myHeap []*ListNode
func (mh myHeap) Len() int {
return len(mh)
}
func (mh myHeap) Swap(i, j int) {
mh[i], mh[j] = mh[j], mh[i]
}
func (mh myHeap) Less(i, j int) bool {
return mh[i].Val < mh[j].Val
}
func (mh *myHeap) Push(x any) {
*mh = append(*mh, x.(*ListNode))
}
func (mh *myHeap) Pop() any {
x := (*mh)[mh.Len()-1]
*mh = (*mh)[:mh.Len()-1]
return x
}
func mergeKLists(lists []*ListNode) *ListNode {
var dummy, tail, node *ListNode
dummy = new(ListNode)
tail = dummy
h := myHeap{}
heap.Init(&h)
for _, list := range lists {
if list == nil {
continue
}
heap.Push(&h, list)
}
for h.Len() > 0 {
node = heap.Pop(&h).(*ListNode)
tail.Next = node
tail = tail.Next
if node.Next != nil {
heap.Push(&h, node.Next)
}
}
return dummy.Next
}
图示
思路 2
暴力解决:保证 lists 中没有 nil 节点,然后每次遍历找最小节点下标,使用尾插法插入到新的链表尾部。然后移动该节点并判断是否为 nil,如果是则从 lists 中移除,当 lists 为空时,处理结束。
1、将非 nil 节点加入到新的 lists 切片中
2、找到本轮最小值和所在的下标,插入到新链表的末尾
3、更新 lists 数组
4、返回新链表头结点(哑节点之后第一个节点)
代码
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func mergeKLists(lists []*ListNode) *ListNode {
dummy := &ListNode{}
tail := dummy
newList := []*ListNode{}
for i := 0; i < len(lists); i++ {
if lists[i] != nil {
newList = append(newList, lists[i])
}
}
for len(newList) != 0 {
target, index := newList[0], 0
for i := 1; i < len(newList); i++ {
if newList[i].Val < target.Val {
target = newList[i]
index = i
}
}
tail.Next = target
tail = tail.Next
newList[index] = newList[index].Next
if newList[index] == nil {
newList = append(newList[:index], newList[index+1:]...)
}
}
return dummy.Next
}
思路3
暴力算力最坏情况下空间复杂度达到了 O(n),使用下面方法可以使用常数级别空间复杂度即可解决。
- 使用哑节点和尾插法重新构造新链表
- 两个辅助变量,分别用来存储本轮最小的元素值和本轮最小元素值在lists数组中的索引
- 将最小元素值使用尾插法插入到新链表尾部并更新lists链表
代码
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func mergeKLists(lists []*ListNode) *ListNode {
var dummy, tail *ListNode
var minValue, minIndex int
dummy = &ListNode{}
tail = dummy
for {
minValue, minIndex = 10001, 0
for idx, list := range lists {
if list == nil {
continue
}
if list.Val < minValue {
minValue = list.Val
minIndex = idx
}
}
if minValue == 10001 {
break
}
tail.Next = lists[minIndex]
tail = tail.Next
lists[minIndex] = lists[minIndex].Next
}
return dummy.Next
}