1. 题目解析与需求拆解
这道题目来自LeetCode热题100的第2题"两数相加",属于链表操作类的基础算法题。题目要求我们处理两个非空链表,它们各自代表一个逆序存储的非负整数,需要将这两个数相加并以相同形式返回结果链表。
举个例子,如果输入是链表A:2->4->3和链表B:5->6->4,那么它们实际代表的数字分别是342和465。相加结果是807,我们需要返回链表C:7->0->8。这种逆序存储的设计其实降低了题目难度,因为数字的个位正好对应链表头,符合我们日常加法从低位开始的运算习惯。
2. 核心算法思路
2.1 模拟竖式加法
这道题最直接的解法就是模拟我们小学学过的竖式加法。我们需要同时遍历两个链表,逐位相加并处理进位。具体来说有以下几个关键点:
- 初始化一个哑节点(dummy node)作为结果链表的起始点,这样可以避免处理头节点的特殊情况
- 使用一个变量carry来记录进位值,初始为0
- 同时遍历两个链表,直到两个链表都到达末尾且没有剩余进位
- 每次迭代时:
- 计算当前位的和:链表A当前节点的值 + 链表B当前节点的值 + carry
- 确定当前位的值:sum % 10
- 更新进位:carry = sum // 10
- 创建新节点并连接到结果链表
- 移动所有链表指针到下一个节点
2.2 边界情况处理
在实际编码中,有几个边界情况需要特别注意:
- 两个链表长度不等时,短链表遍历完后要继续处理长链表剩余部分
- 最后如果还有进位(carry > 0),需要额外创建一个节点
- 输入链表可能为空(虽然题目说明是非空链表,但好的习惯是防御性编程)
3. 代码实现与详细注释
# Definition for singly-linked list. # class ListNode: # def __init__(self, val=0, next=None): # self.val = val # self.next = next class Solution: def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]: dummy = ListNode() # 创建哑节点作为结果链表的起始点 current = dummy # 当前节点指针 carry = 0 # 进位初始化为0 # 遍历直到两个链表都到达末尾且没有剩余进位 while l1 or l2 or carry: # 获取当前节点的值,如果节点为空则视为0 val1 = l1.val if l1 else 0 val2 = l2.val if l2 else 0 # 计算当前位的和 total = val1 + val2 + carry carry = total // 10 # 计算新的进位 digit = total % 10 # 计算当前位的值 # 创建新节点并连接到结果链表 current.next = ListNode(digit) current = current.next # 移动链表指针 if l1: l1 = l1.next if l2: l2 = l2.next return dummy.next # 返回哑节点的下一个节点,即真正的结果链表头4. 复杂度分析与优化空间
4.1 时间复杂度
算法的时间复杂度是O(max(m,n)),其中m和n分别是两个输入链表的长度。因为我们需要遍历两个链表中较长的那个,且每个节点只被访问一次。
4.2 空间复杂度
空间复杂度也是O(max(m,n)),因为我们需要创建一个新的链表来存储结果,最坏情况下结果链表的长度会比输入链表中最长的那个多1(因为有进位)。
4.3 可能的优化方向
虽然这个解法已经相当高效,但仍有几个可能的优化点:
- 可以尝试复用较长的输入链表来存储结果,减少内存分配
- 对于特别长的链表,可以考虑并行计算(虽然对于算法题来说不太必要)
- 如果输入链表是正序存储的(即头节点是最高位),可以考虑使用栈来反转链表
5. 常见错误与调试技巧
5.1 常见错误类型
在解决这个问题时,新手常犯的错误包括:
- 忘记处理最后的进位,导致结果少一位
- 在链表长度不等时,没有正确处理其中一个链表已经遍历完的情况
- 没有使用哑节点,导致头节点处理逻辑复杂
- 在移动链表指针时没有检查是否为空,导致空指针异常
5.2 调试技巧
当你的代码出现问题时,可以尝试以下调试方法:
- 使用简单的测试用例,如两个一位数的链表相加
- 打印中间变量,特别是carry的值和当前节点的值
- 手动模拟算法执行过程,在纸上画出链表的变化
- 检查循环终止条件是否正确,确保所有情况都被覆盖
6. 扩展思考与实际应用
6.1 变种问题
这道题目有几个有趣的变种值得思考:
- 如果链表存储的数字是正序的(即头节点是最高位),如何解决?
- 如果允许链表中有负数,该如何处理?
- 如果不是十进制,而是其他进制(如二进制)的加法,算法需要如何调整?
6.2 实际应用场景
链表加法在实际中有多种应用:
- 大整数运算:当数字太大无法用基本数据类型表示时,可以用链表存储
- 多项式相加:多项式的系数可以用链表存储,加法算法类似
- 某些加密算法中需要处理大数的运算
提示:在面试中,面试官可能会要求你解释算法的每一步,所以务必理解透彻每个细节。同时,准备好讨论时间/空间复杂度以及可能的优化方向。