1.问题描述
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = []
输出:[]
示例 3:
输入:l1 = [], l2 = [0]
输出:[0]
2.难度等级
Easy。
3.热门指数
★★★★★
出题公司:阿里、腾讯、字节。
4.解题思路
4.1 迭代
假设两个有序的单链表 list1 与 list2。
因为两个链表有序,所以遍历两个链表选择值较小的结点链接到结果链表中即可。当一个节点被添加到结果链表之后,将对应链表中的节点向后移一位。
为了简化对结果链表边界条件的判断,可以引入哨兵结点。哨兵结点的 Next 指针便是结果链表的头结点。
- 遍历 list1 或 list2 链表,选择 list1 与 list2 链表当前结点值较小的结点,挂接到结果链表,并将较小结点后移一位。
- 如果有一个为空,结束遍历,则将未遍历完的链表,直接挂接到结果链表。
Golang:
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func mergeTwoLists(list1 *ListNode, list2 *ListNode) *ListNode {
// 哨兵结点。
preHead := &ListNode{}
cur := preHead
// 遍历两个有序链表。
for list1 != nil && list2 != nil {
if list1.Val < list2.Val {
cur.Next = list1
list1 = list1.Next
} else {
cur.Next = list2
list2 = list2.Next
}
cur = cur.Next
}
// 合并剩余链表。
if list1 != nil {
cur.Next = list1
} else {
cur.Next = list2
}
return preHead.Next
}
C++:
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* preHead = new ListNode(-1);
ListNode* prev = preHead;
while (l1 != nullptr && l2 != nullptr) {
if (l1->val < l2->val) {
prev->next = l1;
l1 = l1->next;
} else {
prev->next = l2;
l2 = l2->next;
}
prev = prev->next;
}
// 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
prev->next = l1 == nullptr ? l2 : l1;
return preHead->next;
}
};
4.1 递归
我们直接将以上递归过程建模,同时需要考虑边界情况。
如果 l1 或者 l2 一开始就是空链表 ,那么没有任何操作需要合并,所以我们只需要返回非空链表。否则,我们要判断 l1 和 l2 哪一个链表的头节点的值更小,然后递归地决定下一个添加到结果里的节点。如果两个链表有一个为空,递归结束。
C++
ListNode* mergeTwoLists(ListNode* head1, ListNode* head2) {
if (head1 == NULL) {
return head2;
} else if(head2 == NULL) {
return head1;
}
ListNode* mergeHead = NULL;
if(head1->value < head2->value) {
mergeHead=head1;
mergeHead->next=mergeOrderedLinkedListRecursion(head1->next,head2);
} else {
mergeHead=head2;
mergeHead->next=mergeOrderedLinkedListRecursion(head1,head2->next);
}
return mergeHead;
}