剑指 Offer(第2版)面试题 25:合并两个排序的链表
剑指 Offer(第2版)面试题 25:合并两个排序的链表
题目来源:36. 合并两个排序的链表
解法1:递归
代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution
{
public:
ListNode *merge(ListNode *l1, ListNode *l2)
{
// 特判
if (l1 == nullptr)
return l2;
if (l2 == nullptr)
return l1;
ListNode *mergeHead = nullptr;
if (l1->val <= l2->val)
{
mergeHead = l1;
mergeHead->next = merge(l1->next, l2);
}
else
{
mergeHead = l2;
mergeHead->next = merge(l1, l2->next);
}
return mergeHead;
}
};
复杂度分析:
时间复杂度:O(len1+len2),其中 len1 是链表 l1 的长度, len2 是链表 l2 的长度。因为每次调用递归都会去掉 l1 或者 l2 的头结点,(直到至少有一个链表为空),函数 merge 至多只会递归调用每个节点一次。因此,时间复杂度取决于合并后的链表长度,即 O(len1+len2)。
空间复杂度:O(len1+len2),其中 len1 是链表 l1 的长度, len2 是链表 l2 的长度。递归调用 merge 函数时需要消耗栈空间,栈空间的大小取决于递归调用的深度。结束递归调用时 merge 函数最多调用 len1+len2 次,因此空间复杂度为 O(len1+len2)。
解法2:迭代
设置两个指针 p1 和 p2 分别指向 l1 和 l2 的开头,模拟整个过程。
当一个指针为空时,说明已经遍历到了该链表的末尾,将另一个链表直接插入 merge 链表中即可。
代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution
{
public:
ListNode *merge(ListNode *l1, ListNode *l2)
{
// 特判
if (l1 == nullptr)
return l2;
if (l2 == nullptr)
return l1;
ListNode *dummy = new ListNode(-1);
ListNode *cur = dummy;
ListNode *p1 = l1, *p2 = l2;
while (p1 && p2)
{
if (p1->val <= p2->val)
{
cur->next = p1;
p1 = p1->next;
}
else
{
cur->next = p2;
p2 = p2->next;
}
cur = cur->next;
}
if (p1 == nullptr)
cur->next = p2;
if (p2 == nullptr)
cur->next = p1;
return dummy->next;
}
};
复杂度分析:
时间复杂度:O(len1+len2),其中 len1 是链表 l1 的长度, len2 是链表 l2 的长度。
空间复杂度:O(1)。