将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
我的算法实现:
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
export var mergeTwoLists = function (l1, l2) {
if (!l1) return l2;
else if (!l2) return l1;
let head = l1.val > l2.val ? l2 : l1;
let node = head;
for (let p = l1, q = l2; p !== null || q !== null; ) {
if (p === null) {
node.next = q;
return head;
} else if (q === null) {
node.next = p;
return head;
} else if (p.val > q.val) {
let temp1 = q.next;
node.next = q;
node = q;
q.next = null;
q = temp1;
} else {
let temp1 = p.next;
node.next = p;
node = p;
p.next = null;
p = temp1;
}
}
node.next = null;
return head;
};
我的实现代码太多了,虽然显示的是超过了百分之八十的人,但我不满意。
官网的实现非常好,我特别喜欢的是递归的实现,这次同样的,我也想到了递归,可是想了好久还是没想到怎么实现这个递归: 合并两个有序链表
写递归的具体思路需要总结归纳,不然下次还是无法实现。
先看看这次官网的递归方法:
var mergeTwoLists = function(l1, l2) {
if (l1 === null) {
return l2;
} else if (l2 === null) {
return l1;
} else if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
};
首先定义一下函数的含义:给定两个节点,返回两个节点的值小的那个节点。那么首先考虑特殊情况:
- 如果其中一个为空,那么直接返回另一个节点;
- 如果两个都不为空,那么看前一个节点小的情况,如果前一个节点的确小于,那么返回前一个;
- 如果后面个节点大,那么就返回后面的那个节点。
所以函数应该是下面的样子:
var mergeTwoLists = function(l1, l2) {
if (l1 === null) {
return l2;
} else if (l2 === null) {
return l1;
} else if (l1.val < l2.val) {
return l1;
} else {
return l2;
}
};
现在再扩展到如果是一组数据,除了返回最小的那个节点,还需要将当前的节点的下一个节点指向下一个最小的节点,也就是下面这样:
var mergeTwoLists = function(l1, l2) {
if (l1 === null) {
return l2;
} else if (l2 === null) {
return l1;
} else if (l1.val < l2.val) {
l1.next = /*比较下面两个节点*/
return l1;
} else {
l2.next = /*比较下面两个节点*/
return l2;
}
};
由于当前函数的功能正好满足得到两个节点的最小那个节点,所以可以直接调用自己。于是就得到了前面的递归函数。我们使用这个方法来看昨天官方的递归函数。
// 链表的反转
var reverseList = function (head) {
if (!head || !head.next) {
return head;
}
let node = reverseList(head.next);
head.next.next = head;
head.next = null;
return node;
};
- 函数的功能是将传入节点的下一个节点指向传入的节点,并让传入节点指向空,也就是实现反转,并返回新的头节点;
- 首先判断极端的情况,如果当前传入的节点和传入节点的下一个节点为空,那么直接返回传入的节点;
- 如果满足上面的情况,那么传入节点的下下个节点等于当前节点:
head->next->next = head; - 以此类推就可以得到这样的函数,只不过实现起来还是麻烦的,还是需要多练习。
来源:力扣(LeetCode)