两个合并,思路&代码
非递归,排除一些边界值,同时利用两个指针进行比较(升序)将小的节点摘下来重新拼接成新的链表节点
// 非递归,排除一些边界值,同时利用两个指针进行比较(升序)将小的节点摘下来重新拼接成新的链表节点
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
if l1 == nil && l2 == nil {
return nil
}
if l1 == nil {
return l2
}
if l2 == nil {
return l1
}
var p, q, h, t *ListNode = l1, l2, nil, nil
for p != nil && q != nil {
if p.Val <= q.Val {
if h == nil {
h = p
t = h
} else {
t.Next = p
t = p
}
p = p.Next
} else {
if h == nil {
h = q
t = h
} else {
t.Next = q
t = q
}
q = q.Next
}
}
// 最后那个链表有多余的直接拼接再新链表后面即可
if p == nil {
t.Next = p
} else if q == nil {
t.Next = q
}
return h
}
递归:
递归,同比每次循环,都是两个节点再比较,并且每次返回的都满足条件的节点指针,那么就可以将循环拆每次传递两个节点进行相关条件的比较递归要考虑返回条件,该题目中,递归返回条件就是某个链表遍历完了,则返回另一个链表当前的节点指针
func mergeLink(l1, l2 *ListNode) *ListNode {
if l1 == nil {
return l2
}
if l2 == nil {
return l1
}
if l1 == nil && l2 == nil {
return nil // 边界值,第一次两个nil进来
}
var h *ListNode
if l1.Val <= l2.Val {
h = l1
h.Next = mergeLink(h.Next, l2) // 本地调用中,函数返回上一次调用满足条件的节点指针
} else {
h = l2
h.Next = mergeLink(h.Next, l1)
}
return h
}
N个有序连标合并,思路&代码
/*
合并n个已经排序的链接表(每个链表都随有序,比如asc) 思路:都是已经拍过序列,利用分治的思想,进行拆分,最小可以拆成合并两个有序链表那样,最后再将每个小节的合并起来的思路处理
*/
func mergeNLink(linkList []*ListNode) *ListNode {
if len(linkList) == 0 {
return nil
}
if len(linkList) == 1 {
return linkList[0]
}
if len(linkList) == 2 {
return mergeTwoLists(linkList[0], linkList[1])
}
// 进行拆分
mid := len(linkList) >> 1
leftLink := make([]*ListNode, mid)
rightLink := make([]*ListNode, len(linkList)-mid)
copy(leftLink, linkList[0:mid])
copy(rightLink, linkList[mid:])
// 利用两两合并,再利用自身递归不断的拆分,直到达到返回条件,不能再拆分为止
return mergeTwoLists(mergeNLink(leftLink), mergeNLink(rightLink))
}