在问 · 算法题解

2. 两数相加

中等链表逐位模拟(迭代)力扣原题 ↗

题目描述

输入两个非空链表 l1 和 l2,各自表示一个非负整数。链表从头到尾依次存放该数的个位、十位、百位……,每个节点只放一位数字。

把这两个整数相加,用同样的逆序链表形式返回它们的和。

除了数字 0 本身,两个数都没有前导零。

示例 1
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]

解释:两数分别是 342 和 465,和为 807,逆序存放就是 [7,0,8]。

示例 2
输入:l1 = [0], l2 = [0]
输出:[0]

解释:0 + 0 = 0。

示例 3
输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

解释:9999999 + 9999 = 10009998,逆序存放为 [8,9,9,9,0,0,0,1]。

数据范围

  • 每个链表的节点数在 [1, 100] 之间
  • 0 <= Node.val <= 9
  • 链表表示的数没有前导零。

解题思路:逐位模拟(迭代)

逐位加两个节点值及进位,用 divmod 同时计算新进位和个位。

为什么正确

结果前缀已经正确表示所有处理过的低位,carry 是传给下一位的进位。

复杂度分析

时间 O(max(m,n)),额外空间 O(1),输出空间 O(max(m,n))。

易错点

循环条件必须包括 carry,否则会漏掉最高位进位。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def addTwoNumbers(self, l1, l2):
        dummy = ListNode(0)
        tail = dummy
        carry = 0
        while l1 or l2 or carry:
            total = carry
            if l1:
                total += l1.val
                l1 = l1.next
            if l2:
                total += l2.val
                l2 = l2.next
            carry, digit = divmod(total, 10)
            tail.next = ListNode(digit)
            tail = tail.next
        return dummy.next

载入编辑器,自己跑一遍 →

其他解法

两种做法都逐位相加并传递进位;迭代版额外空间 O(1),递归版写法更贴近定义但需要调用栈。

解法 2:递归逐位相加 时间 O(max(m,n)),空间 O(max(m,n))

定义 add(a, b, carry):返回两条剩余链表加上进位后的结果链表。三者都为空时返回空。否则算出当前位 total,新建节点存 total % 10,它的 next 交给 add(a.next, b.next, total / 10)。

不需要哑节点和尾指针,代码直接对应“当前位 + 剩余部分”的定义。递归深度等于结果长度,占用 O(max(m,n)) 栈空间。

class Solution:
    def addTwoNumbers(self, l1, l2):
        def add(a, b, carry):
            if not a and not b and not carry:
                return None
            total = carry
            if a:
                total += a.val
                a = a.next
            if b:
                total += b.val
                b = b.next
            node = ListNode(total % 10)
            node.next = add(a, b, total // 10)
            return node
        return add(l1, l2, 0)

链表 专题的其他题目

查看 链表 全部题目 →