合并两个有序链表-递归及迭代实现
题目链接:合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的 – 告诉我们不能重新new节点。
示例1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
示例2:
输入:l1 = [], l2 = [] 输出:[]
1.递归实现
STEP1:重复子问题,及递归函数头的设计
由于两个链表都是升序的,所以我们让list1
和list2
去比较,让其val较小的那个作为头结点;转化为子问题:在新的两条链表中,继续去找新的头结点…
STEP2:只关心当前子问题做的事情
当前子问题做了什么,它将当前的头结点链接到下一个子问题返回的头结点上,我们相信子问题一定能返回正确的头结点。
STEP3:递归终止条件
list1
和list2
有一个为空就返回。
最终代码实现如下:
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
if(list1 == nullptr) return list2;
if(list2 == nullptr) return list1;
ListNode* head = list1;
if(list1->val <= list2->val)
{
head->next = mergeTwoLists(list1->next, list2);
}
else
{
head = list2;
head->next = mergeTwoLists(list1, list2->next);
}
return head;
}
};
时间复杂度: O(n + m),n 和 m 分别为两个链表的长度。每一次递归都会去掉一个list1
或者list2
头节点,因此时间复杂度取决于两链表加起来的长度。
空间复杂度: O(n + m)。递归调用函数会消耗栈空间,消耗栈空间的大小和递归调用函数的深度有关,当递归调用结束时,mergeTwoLists
函数最多被调用 m + n 次。
2.迭代实现
首先定义一个哨兵位的头结点prehead
,这样能方便后序的插入,我们直接将较小的节点插入到哨兵位头结点即可,等待节点链接完毕,返回prehead->next
。
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
if(list1 == nullptr) return list2;
if(list2 == nullptr) return list1;
ListNode* prehead = nullptr, *tail = nullptr;
prehead = new ListNode(-1);
tail = prehead;
while(list1 && list2)
{
if(list1->val <= list2->val)// list1的节点小, 尾差到tail后面
{
tail->next = list1;// tail链接下一个节点
list1 = list1->next;
tail = tail->next;// tail继续走到新链表的后面, 准备链接其他节点
}
else// list2的节点小, 尾差到tail后面
{
tail->next = list2;
list2 = list2->next;
tail = tail->next;
}
}
// 判断一下, 防止遗漏节点
if(list1) tail->next = list1;
else tail->next = list2;
ListNode* ret = prehead->next;
delete prehead;
return ret;
}
};
时间复杂度: O(n + m),n 和 m 分别为两个链表的长度。循环就是在遍历两条链表,所以时间复杂度就是两条链表的和。
空间复杂度: O(1)。只开辟了哨兵为头结点和其他若干个变量的空间。