TL;DR
把两个链表洗牌兼并成一个,系列目次见 前言和目次 。
需求
完成函数 shuffleMerge()
把两个链表兼并成一个。新链表的节点是交织从两个链表中取的。这叫洗牌兼并。举个例子,当传入的链表为 1 -> 2 -> 3 -> null
和 7 -> 13 -> 1 -> null
时,兼并后的链表为 1 -> 7 -> 2 -> 13 -> 3 -> 1 -> null
。假如兼并历程当中一个链表的数据先取完了,就从另一个链表中取剩下的数据。这个函数应当返回一个新链表。
var first = 3 -> 2 -> 8 -> null
var second = 5 -> 6 -> 1 -> 9 -> 11 -> null
shuffleMerge(first, second) === 3 -> 5 -> 2 -> 6 -> 8 -> 1 -> 9 -> 11 -> null
假如参数之一为空,应当直接返回另一个链表(纵然另一个链表也为空),不需要抛非常。
递归解法 1
代码以下:
function shuffleMerge(first, second) {
if (!first || !second) return first || second
const list = new Node(first.data, new Node(second.data))
list.next.next = shuffleMerge(first.next, second.next)
return list
}
解题思绪是,起首推断是不是有一个链表为空,有就返回另一个,完毕递归。这个推断过了,下面肯定是两个链表都不为空的状况。我们顺次从两个链表中取第一个节点组合成新链表,然后递归 shuffleMerge
两个链表的后续节点,并把效果衔接到 list
背面。这段代码基础跟问题形貌的意义一致。
递归解法 2
在上面的基础上我们还能做个更智慧的版本,代码以下:
function shuffleMergeV2(first, second) {
if (!first || !second) return first || second
return new Node(first.data, shuffleMerge(second, first.next))
}
经由历程简朴的换取 first
和 second
的递次,我们能把递归历程从 “先取 first 的首节点再取 second 的首节点” 变成 “总老是取 first 的首节点” 。解法 1 中的三行代码简化成了一行。
轮回解法
轮回实在才是本题的考点,由于这题主如果考指针(援用)操纵。尤其是把 “顺次挪动两个链表的指针” 写进一个轮回里。不过上个解法中换取两个链表递次的体式格局也能够用到这里。代码以下:
function shuffleMergeV3(first, second) {
const result = new Node()
let pr = result
let [p1, p2] = [first, second]
while (p1 || p2) {
if (p1) {
pr.next = new Node(p1.data)
pr = pr.next
p1 = p1.next
}
[p1, p2] = [p2, p1]
}
return result.next
}
起首我们天生一个 dummy node result
,同时竖立一个 pr
代表 result
的尾节点(轻易插进去)。两个链表的指针分别叫 p1
和 p2
。在每次轮回中我们都把 p1
的节点数据写到 result
链表的末端,然后修正指针指向下一个节点。经由历程 12 行的换取指针,我们能够保证下一次轮回就是对另一个链表举行操纵了。如许一向遍历到两个链表末端,返回 result.next
完毕。