LeetCode hot100:021 合并两个有序链表:两种解法的深入剖析
问题描述:
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例2:
输入:l1 = [], l2 = []
输出:[]
示例3:
输入:l1 = [], l2 = [0]
输出:[0]
解决方法:
方法一:迭代法
算法思路:
-
使用临时头节点避免处理头节点的特殊情况
-
比较两个链表当前节点的值,将较小的节点连接到结果链表
-
移动指针到下一个节点
-
当某个链表遍历完后,直接连接另一个链表的剩余部分
代码实现:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: # 创建临时头结点Temp = ListNode(0)current = Temp# 遍历两个链表while list1 and list2:if list1.val <= list2.val:current.next = list1list1 = list1.nextelse:current.next = list2list2 = list2.nextcurrent = current.next# 连接剩余部分current.next = list1 if list1 else list2return Temp.next
复杂度分析:
- 时间复杂度:O(n + m)
- 空间复杂度:O(1)
方法二:递归法
算法思路:
-
基本情况:如果任一链表为空,直接返回另一个链表
-
递归情况:比较两个链表的头节点值,选择较小的节点作为当前节点
-
将该节点的next指针指向剩余链表合并的结果
-
返回当前节点
代码实现:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:# 递归# 基本情况:如果任一链表为空,返回另一个链表if not list1:return list2elif not list2:return list1# 递归情况:比较头节点,选择较小的节点elif list1.val <= list2.val:list1.next = self.mergeTwoLists(list1.next,list2)return list1else:list2.next = self.mergeTwoLists(list1,list2.next)return list2
复杂度分析:
- 时间复杂度:O(n + m)
- 空间复杂度:O(n + m)(递归调用栈)
问题详解:
对于递归(核心是分治):理解 return 的含义
-
递归是"自底向上"构建:从最深层开始,逐层返回结果,每层结果存在递归工作栈中
-
return是连接各层的桥梁:没有return,各层结果无法传递 -
最终结果需要返回:最外层的调用需要收到最终合并的链表头
对于迭代,核心在于新建头节点,就可以避免对两个链表头节点的讨论
总结:
| 特性 | 迭代法 | 递归法 |
| 时间复杂度 | O(n+m) | O(n+m) |
| 空间复杂度 | O(1) | O(n+m) |
| 代码简洁度 | 一般 | 较好 |
| 可读性 | 容易理解 | 需要递归思维 |
| 适用场景 | 推荐 | 链表较短时 |
-
迭代法更实用:空间效率更高,适合处理长链表,是实际开发中的首选
-
递归法更优雅:代码简洁,体现了分治思想,适合理解递归概念
-
核心技巧:使用新建节点简化边界处理,理解指针操作的本质
合并有序链表是链表操作中的经典问题,掌握这两种解法对于理解链表操作和递归思想都有重要意义。
