LeetCode刷题——算法学习计划(入门部分)
题目描述
思路介绍
题目看起来很简单,但对于不懂算法的我来说,这简直是天书,不过看完网友或官方的题解,又能瞬间理解(因为代码量少😂)
采用递归,也可称为深度优先搜索,将两个头节点放入递归函数,
第一层递归:如果链表l1
的值比l2
小,则将链表l1
的下个节点(l1->next
)和l2
进行合并,即进行第二层递归,由于合并后的链表头节点为l1
,所以在第一层递归后要返回l1
;同理,如果第一层递归中l2
的值比l1
小,就对l2->next
和l1
进行递归返回l2
。
第二层递归,在第一层递归中,已经选出了值最小的节点,接下来要选择第二小的,再返回到第一小的节点后面。
第三层递归。。。第n层递归,规律和前面两层相同,直到l1
或l2
为空节点,此时将另一个非空节点返回,递归结束。
我的第一次正确提交
虽然思路不是自己的,但代码是自己(手)写(抄)的
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2)
{
if(l1 == NULL)
return l2;
else if(l2 == NULL)
return l1;
if(l1->val < l2->val)
{
l1->next = mergeTwoLists(l1->next, l2);
return l1;
}
else
{
l2->next = mergeTwoLists(l1, l2->next);
return l2;
}
}
官方版本
方法一:递归
如果 l1 或者 l2 一开始就是空链表 ,那么没有任何操作需要合并,所以我们只需要返回非空链表。否则,我们要判断 l1 和 l2 哪一个链表的头节点的值更小,然后递归地决定下一个添加到结果里的节点。如果两个链表有一个为空,递归结束。
——作者:LeetCode-Solution——链接——来源:力扣(LeetCode)
官方没给C语言版本,直接上C++吧,都差不多(把类的声明去掉就能当C函数来用了)
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if (l1 == nullptr) {
return l2;
} else if (l2 == nullptr) {
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;
}
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/he-bing-liang-ge-you-xu-lian-biao-by-leetcode-solu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复杂度分析
时间复杂度:O(n+m),其中 n 和 m 分别为两个链表的长度。因为每次调用递归都会去掉 l1 或者 l2 的头节点(直到至少有一个链表为空),函数 mergeTwoList 至多只会递归调用每个节点一次。因此,时间复杂度取决于合并后的链表长度,即 O(n+m)。
空间复杂度:O(n+m),其中 n 和 m 分别为两个链表的长度。递归调用 mergeTwoLists 函数时需要消耗栈空间,栈空间的大小取决于递归调用的深度。结束递归调用时 mergeTwoLists 函数最多调用 n+m 次,因此空间复杂度为 O(n+m)。
——作者:LeetCode-Solution——链接——来源:力扣(LeetCode)
方法二:迭代
迭代?不懂,以后想了解的时候再看吧,感兴趣的可以看看官方题解
官方没给C语言版本,直接上C++吧,都差不多(把类的声明去掉就能当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;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/he-bing-liang-ge-you-xu-lian-biao-by-leetcode-solu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复杂度分析
时间复杂度:O(n+m),其中 n 和 m 分别为两个链表的长度。因为每次循环迭代中,l1 和 l2 只有一个元素会被放进合并链表中, 因此 while 循环的次数不会超过两个链表的长度之和。所有其他操作的时间复杂度都是常数级别的,因此总的时间复杂度为 O(n+m)。
空间复杂度:O(1)。我们只需要常数的空间存放若干变量。
——作者:LeetCode-Solution——链接——来源:力扣(LeetCode)