21. 合并两个有序链表
题目描述
输入两个按非递减顺序排列的链表 list1 和 list2,链表用数组表示。
把两个链表的所有节点接成一个新链表,仍保持非递减顺序,返回新链表的头节点。新链表直接由原有节点拼接而成。结果为空时返回 null。
示例 1
输入:list1 = [1,2,4], list2 = [1,3,4] 输出:[1,1,2,3,4,4]
解释:按大小交替取两个链表的节点,得到 [1,1,2,3,4,4]。
示例 2
输入:list1 = [], list2 = [] 输出:[]
解释:两个链表都为空,结果也为空。
示例 3
输入:list1 = [], list2 = [0] 输出:[0]
解释:一个为空,结果就是另一个链表。
数据范围
- 两个链表的节点数都在
[0, 50]之间 -100 <= Node.val <= 100list1和list2都已按非递减顺序排好。
解题思路:哑节点 + 迭代合并
用哑节点保存头部,每次接入两个当前节点中较小者,最后接上剩余链表。
为什么正确
tail 之前已经合并的前缀有序,且包含所有已经取出的节点。
复杂度分析
时间 O(m+n),额外空间 O(1)。
易错点
返回 dummy.next;不要返回最后的 tail。
参考代码
Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。
class Solution:
def mergeTwoLists(self, list1, list2):
dummy = ListNode(0)
tail = dummy
while list1 and list2:
if list1.val <= list2.val:
tail.next = list1
list1 = list1.next
else:
tail.next = list2
list2 = list2.next
tail = tail.next
tail.next = list1 or list2
return dummy.nextclass Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
while (list1 != null && list2 != null) {
if (list1.val <= list2.val) {
tail.next = list1;
list1 = list1.next;
} else {
tail.next = list2;
list2 = list2.next;
}
tail = tail.next;
}
tail.next = list1 != null ? list1 : list2;
return dummy.next;
}
}class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode* dummy = new ListNode(0);
ListNode* tail = dummy;
while (list1 && list2) {
if (list1->val <= list2->val) {
tail->next = list1;
list1 = list1->next;
} else {
tail->next = list2;
list2 = list2->next;
}
tail = tail->next;
}
tail->next = list1 ? list1 : list2;
return dummy->next;
}
};func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {
dummy := &ListNode{}
tail := dummy
for list1 != nil && list2 != nil {
if list1.Val <= list2.Val {
tail.Next = list1
list1 = list1.Next
} else {
tail.Next = list2
list2 = list2.Next
}
tail = tail.Next
}
if list1 != nil {
tail.Next = list1
} else {
tail.Next = list2
}
return dummy.Next
}var mergeTwoLists = function(list1, list2) {
const dummy = new ListNode(0);
let tail = dummy;
while (list1 && list2) {
if (list1.val <= list2.val) {
tail.next = list1;
list1 = list1.next;
} else {
tail.next = list2;
list2 = list2.next;
}
tail = tail.next;
}
tail.next = list1 || list2;
return dummy.next;
};function mergeTwoLists(list1: ListNode | null, list2: ListNode | null): ListNode | null {
const dummy = new ListNode(0);
let tail = dummy;
while (list1 && list2) {
if (list1.val <= list2.val) {
tail.next = list1;
list1 = list1.next;
} else {
tail.next = list2;
list2 = list2.next;
}
tail = tail.next!;
}
tail.next = list1 || list2;
return dummy.next;
};其他解法
同一种归并思想的两种实现:迭代版用哑节点和尾指针逐个接,空间 O(1);递归版更简洁,但占用栈空间。
解法 2:递归合并 时间 O(m+n),空间 O(m+n)
若其中一个链表为空,直接返回另一个。否则取两个头节点中较小的那个,把它的 next 设为「其余部分递归合并的结果」,然后返回它。
定义式的写法,代码极短,是理解链表递归的好例子。递归深度为 m+n,需要 O(m+n) 栈空间,链表很长时可能栈溢出。
class Solution:
def mergeTwoLists(self, list1, list2):
if not list1:
return list2
if not list2:
return list1
if list1.val <= list2.val:
list1.next = self.mergeTwoLists(list1.next, list2)
return list1
list2.next = self.mergeTwoLists(list1, list2.next)
return list2class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if (list1 == null) return list2;
if (list2 == null) return list1;
if (list1.val <= list2.val) {
list1.next = mergeTwoLists(list1.next, list2);
return list1;
}
list2.next = mergeTwoLists(list1, list2.next);
return list2;
}
}class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
if (!list1) return list2;
if (!list2) return list1;
if (list1->val <= list2->val) {
list1->next = mergeTwoLists(list1->next, list2);
return list1;
}
list2->next = mergeTwoLists(list1, list2->next);
return list2;
}
};func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {
if list1 == nil {
return list2
}
if list2 == nil {
return list1
}
if list1.Val <= list2.Val {
list1.Next = mergeTwoLists(list1.Next, list2)
return list1
}
list2.Next = mergeTwoLists(list1, list2.Next)
return list2
}var mergeTwoLists = function(list1, list2) {
if (!list1) return list2;
if (!list2) return list1;
if (list1.val <= list2.val) {
list1.next = mergeTwoLists(list1.next, list2);
return list1;
}
list2.next = mergeTwoLists(list1, list2.next);
return list2;
};function mergeTwoLists(list1: ListNode | null, list2: ListNode | null): ListNode | null {
if (!list1) return list2;
if (!list2) return list1;
if (list1.val <= list2.val) {
list1.next = mergeTwoLists(list1.next, list2);
return list1;
}
list2.next = mergeTwoLists(list1, list2.next);
return list2;
};