leetcode#21两个有序链表的合并
一.题目
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = []
输出:[]
示例 3:
输入:l1 = [], l2 = [0]
输出:[0]
提示:两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按非递减顺序 排序
二.解法:用一个辅助链表
2.1直观循环解法:
由于链表的遍历不能回头,所以我采取使用辅助链表,在两个链表遍历的时候通过比较,将较小的一个插到辅助链表。这样只需用l1l2和辅助链表通过一次遍历实现合并。
2.1.1复杂度分析
时间复杂度:对于每个数据做一次比较插入O(n)
空间复杂度:只需两个指针的空间O(1)
2.1.2代码
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1==NULL)
return l2;
if(l2==NULL)
return l1;//特殊
ListNode* head;//初始化
if((l1->val)<=(l2->val))
{head=l1;
l1=l1->next;
}
else
{head=l2;
l2=l2->next;//若不更新则可能造成next再次指向自己,编译器报错
}//为了避免这种情况,l1l2的第一个val相等时,赋值与插入应选不同的l
ListNode* end=head;
while(l2!=NULL&&l1!=NULL)//插入
{
if((l1->val)<(l2->val))
{ end->next=l1;
l1=l1->next;}
else
{
end->next=l2;
l2=l2->next;
}
end=end->next;
}
if(l2==NULL)
end->next=l1;
else
end->next=l2;
return head;
}
};
2.2递归解法
可以看出,我们的解法在不断重复“对比插入移动”的动作,
那么我们可以考虑用递归实现合并。
图片来源:leetcode腐烂的橘子:一看就会,一写就废?详解递归
通过倒着思考倒着画图
可以看出,导火索是其中一个I1或l2为空,重复的步骤是返回那个值较小的节点的指针。
2.2.1复杂度分析
如何计算递归的时间复杂度和空间复杂度呢? 力扣对此进行了 详细介绍 ,其中时间复杂度可以这样计算:
递归的时间复杂度
给出一个递归算法,其时间复杂度 O ( T ) {\mathcal{O}(T)} O(T) 递归调用的数量,记作 R {R} R 计算的时间复杂度 O ( s ) {\mathcal{O}(s)} O(s)那么 O ( T ) = R ∗ O ( s ) O(T)=R∗O(s) O(T)=R∗O(s)
该题的时间复杂度: O ( n ) {\mathcal{O}}(n) O(n)
分析:m,n 为 l1和 l2 的元素个数。递归函数每次去掉一个元素,直到两个链表都为空,因此 R = m + n R=m+n R=m+n在递归函数中只进行了 next 指针的赋值操作,计算的时间复杂度为 O ( 1 ) O(1) O(1)故递归的总时间复杂度为 O ( T ) = R ∗ O ( 1 ) = O ( n ) {\mathcal{O}(T) = R * \mathcal{O}(1)}={\mathcal{O}}( n) O(T)=R∗O(1)=O(n)
空间复杂度
计算整个算法的辅助空间单元的个数
调用的空间中储存常量级数据则
O
(
1
)
O(1)
O(1)
调用的空间中储存n个数据则
O
(
n
)
O(n)
O(n)
调用的空间中储存n^2个数据则
O
(
n
2
)
O(n^2)
O(n2)
该题的空间复杂度
O ( n ) O(n) O(n)
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if (l1 == NULL) {
return l2;
}
if (l2 == NULL) {
return l1;
}
if (l1->val <=l2->val)//使用递归不会有2.1.1中next指自己的情况
{
l1->next = mergeTwoLists(l1->next, l2);//因为这一步将它本身排除了
return l1;
}
else
{
l2->next = mergeTwoLists(l1, l2->next);
return l2;
}
}
};
参考来源:
递归的解法:
作者:z1m
链接:link