21 合并两个有序链表(Easy)
-
方法1:递归
-
思路
- 可以如下递归地定义两个链表里的
merge
操作(忽略边界情况,比如空链表等):\[\left\{\begin{array}{ll} \text {list} 1[0]+\text {merge}(\text {list} 1[1:], \text {list} 2) & \text {list} 1[0]<\text {list} 2[0] \\ \text {list} 2[0]+\text {merge}(\text {list} 1, \text {list} 2[1:]) & \text {otherwise} \end{array}\right. \]
即两个链表头部值较小的一个节点与剩下元素的
merge
操作结果合并- 如果
l1
或者l2
一开始就是空链表 ,那么没有任何操作需要合并,所以只需要返回非空链表。 - 否则,需要判断
l1
和l2
哪一个链表的头节点的值更小,然后递归地决定下一个添加到结果里的节点。如果两个链表有一个为空,递归结束。
- 可以如下递归地定义两个链表里的
-
Code
class Solution { public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { if (!l2) { return l1; } else if (!l1) { return l2; } else if (l1->val > l2->val) { l2->next = mergeTwoLists(l1, l2->next); return l2; } else { l1->next = mergeTwoLists(l1->next, l2); return l1; } } };
-
复杂度分析
- 时间复杂度:\(O(n + m)\),其中 \(n\) 和 \(m\) 分别为两个链表的长度。因为每次调用递归都会去掉
l1
或者l2
的头节点,直到至少有一个链表为空,函数 mergeTwoList 至多只会递归调用每个节点一次。 - 空间复杂度:\(O(n + m)\),其中 \(n\) 和 \(m\) 分别为两个链表的长度。递归调用 mergeTwoLists 函数时需要消耗栈空间,栈空间的大小取决于递归调用的深度。结束递归调用时 mergeTwoLists 函数最多调用 \(n+m\) 次,因此空间复杂度为 \(O(n+m)\)。
- 时间复杂度:\(O(n + m)\),其中 \(n\) 和 \(m\) 分别为两个链表的长度。因为每次调用递归都会去掉
-
-
方法2:迭代
-
思路
- 当
l1
和l2
都不是空链表时,判断l1
和l2
哪一个链表的头节点的值更小,将较小值的节点添加到结果里,当一个节点被添加到结果里之后,将对应链表中的节点向后移一位。 - 设定一个哨兵节点
dummy
,方便返回合并后的链表。维护一个node
指针,不断调整它的next
指针。重复以下过程,直到l1
或者l2
指向了null
:如果l1
当前节点的值小于等于l2
,把l1
当前的节点接在node
节点的后面同时将l1
指针往后移一位。否则,对l2
做同样的操作。不管将哪一个元素接在了后面,都需要将node
向后移一位。 - 在循环终止的时候,
l1
和l2
至多有一个是非空的。由于输入的两个链表都是有序的,只需要将非空链表接在合并链表的后面,并返回合并链表即可
- 当
-
Code
class Solution { public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { //设置哨兵节点和遍历节点 ListNode *dummy = new ListNode(0), *node = dummy; while (l1 && l2) { //获取下一个节点 if (l1->val <= l2->val) { node->next = l1; l1 = l1->next; } else { node->next = l2; l2 = l2->next; } //连接节点 node = node->next; } //合并后l1和l2最多只有一个还未被合并完,直接将链表末尾指向未合并完的链表 node->next = l1 ? l1 : l2; return dummy->next; } };
-
复杂度分析
- 时间复杂度:\(O(n + m)\),其中 \(n\) 和 \(m\) 分别为两个链表的长度。因为每次循环迭代中,
l1
和l2
只有一个元素会被放进合并链表中, 因此while
循环的次数不会超过两个链表的长度之和。 - 空间复杂度:\(O(1)\)
- 时间复杂度:\(O(n + m)\),其中 \(n\) 和 \(m\) 分别为两个链表的长度。因为每次循环迭代中,
-