🔗 合并两个有序链表:像拉拉链一样合并数据
摘要:本文详解 LeetCode 21 题“合并两个有序链表”,通过“虚拟头节点 + 双指针比较”的思路,实现链表合并的优雅解法,附带代码实现与核心知识点解析。
📚 核心知识点:虚拟头节点与双指针
在处理链表合并问题时,我们常面临两个痛点:需要频繁处理头节点的边界情况 和 无法直接访问前驱节点。
虚拟头节点(Dummy Node) 是一个非常实用的技巧:
- 创建一个临时的“哨兵”节点作为新链表的起始点。
- 所有合并操作都接在这个节点之后。
- 最终返回
dummy.next即可得到完整链表。 - 优势:避免了对头节点的特殊判断,让代码更简洁。
双指针比较:
- 两个指针分别指向两个链表的当前节点。
- 比较大小,将较小的节点接在结果链表后。
- 移动对应指针,继续比较,直到其中一个链表为空。
📝 题目解析:LeetCode 21. 合并两个有序链表
题目描述:
将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
💻 代码实现
# 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]:
# 创建虚拟头节点,简化头节点处理
dummy = ListNode()
# 当前节点指针,用于构建新链表
current = dummy
# 双指针遍历两个链表
while list1 and list2:
# 比较大小,将较小节点接在结果链表后
if list1.val <= list2.val:
current.next = list1
list1 = list1.next # 移动 list1 指针
else:
current.next = list2
list2 = list2.next # 移动 list2 指针
current = current.next # 移动结果链表指针
# 处理剩余节点(其中一个链表可能还有剩余)
if list1:
current.next = list1
else:
current.next = list2
# 返回合并后的链表(跳过虚拟头节点)
return dummy.next
🚀 解题思路总结
- 虚拟头节点:创建
dummy节点,避免处理头节点的边界情况。 - 双指针比较:用
current指针构建新链表,list1和list2指针分别遍历两个链表。 - 合并逻辑:比较
list1和list2的当前节点值,将较小的节点接在current后,移动对应指针。 - 处理剩余节点:当其中一个链表遍历完后,将另一个链表的剩余部分直接接在结果链表后。
- 返回结果:返回
dummy.next,即合并后的链表头节点。
📌 关键点提示
- 虚拟头节点:让代码更简洁,避免对头节点的特殊判断。
- 双指针:同时遍历两个链表,比较大小并合并。
- 剩余节点处理:其中一个链表遍历完后,另一个链表的剩余部分直接接在结果链表后。
通过以上步骤,我们可以高效地合并两个有序链表,时间复杂度为 O(m + n),空间复杂度为 O(1)。