刷题笔记——链表合并
今天带来leetcode23题的刷题笔记。这是一道困难题,但整体来说是比较容易的一道。
先来看看原题描述:
23. Merge k Sorted Lists
题目
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
Example :
Input:
[
1->4->5,
1->3->4,
2->6
]
Output: 1->1->2->3->4->4->5->6
题目大意
合并 K 个有序链表
解题思路
借助分治的思想,把 K 个有序链表两两合并即可。相当于是第 21 题的加强版。
解题前先看看21题
21. 合并两个有序链表
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
这道题是道简单题。操作起来也方便,利用和归并排序相同的方式即可。
上手极易,上代码:
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
//这里声明一个root指向第一个结点,最终返回root.Next即可。以防结点的变化,适用于很多情况
root := &ListNode{}
node := root
for l1 != nil && l2 != nil {
if l1.Val < l2.Val {
node.Next = l1
l1 = l1.Next
} else {
node.Next = l2
l2 = l2.Next
}
node = node.Next
}
//循环完,防止出现某条链表没有遍历完的情况,需要额外判断一下。
if l1 != nil {
node.Next = l1
}
if l2 != nil {
node.Next = l2
}
return root.Next
}
这道题需要注意的地方就是注释两点。
再看看23题,k条链表,那么自然不能简单像21题如此处理了。需要对所有链表循环比较。
话不多说,上代码:
func mergeKLists(lists []*ListNode) *ListNode {
// 同样为返回值而声明
root := &ListNode{}
if len(lists) == 0 {
return root.Next
}
node := root
index := 0
for node != nil {
// num为了获取当前最小值
num := math.MaxInt64
for k, v := range lists {
// 判v空即可保证所有节点都被遍历到,不多也不少
if v != nil && v.Val <= num {
num = lists[k].Val
index = k
}
}
if lists[index] == nil {
break
}
node.Next = lists[index]
node = node.Next
lists[index] = lists[index].Next
}
return root.Next
}
这道题如此解法的注意也写在注释上了。
循环虽然好想,但其实代码书写的时候不太容易。那么其他的解题方案?
分治法
分治法是解决此题的较好的方法。
利用21题的两两合并的函数。(这里两两合并也使用分治思想)
上代码:
func mergeKLists(lists []*ListNode) *ListNode {
length := len(lists)
if length < 1 {
return nil
}
if length == 1 {
return lists[0]
}
num := length / 2
left := mergeKLists(lists[:num])
right := mergeKLists(lists[num:])
return mergeTwoLists1(left, right)
}
func mergeTwoLists1(l1 *ListNode, l2 *ListNode) *ListNode {
if l1 == nil {
return l2
}
if l2 == nil {
return l1
}
if l1.Val < l2.Val {
l1.Next = mergeTwoLists1(l1.Next, l2)
return l1
}
l2.Next = mergeTwoLists1(l1, l2.Next)
return l2
}
此种解法借助分治的思想,把k个有序链表两两合并即可。虽然思路上比较难,但代码书写上比较容易。
有兴趣的关注我的公众号,一起学习交流啊