LeetCode 第 2 题「两数相加」
字数 1252 2025-10-26 05:22:27

好的,我们来看 LeetCode 第 2 题「两数相加」


题目描述

给你两个 非空 的链表,分别表示两个非负整数。它们的每位数字都是按照 逆序 方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例 1:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807,逆序存储就是 [7,0,8]

示例 2:

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

解题思路

1. 理解逆序存储的好处

数字在链表中是逆序存放的(个位在链表头部),这样我们在做加法时,可以从链表头部开始逐位相加,正好符合我们手算加法从低位到高位的顺序。

2. 模拟加法过程

加法规则:

  • 从两个链表的头节点开始,将对应位置的数字相加,再加上 上一位的进位值
  • 当前位的和 = l1.val + l2.val + carry
  • 当前位的结果值为 和 % 10,新的进位值为 和 // 10
  • 将结果位的数字作为一个新节点接到结果链表的尾部。
  • 然后指针 l1l2 向后移动一位。

3. 处理链表长度不同的情况

当其中一个链表已经到末尾,而另一个还有节点时,短链表的对应位视为 0。

4. 最后的进位

当两个链表都遍历完后,如果进位值 carry > 0,需要在结果链表最后添加一个值为 carry 的节点。


详细步骤

  1. 创建一个哑节点(dummy node)作为结果链表的头部,这样可以避免处理结果链表为空的情况。
  2. 初始化一个指针 curr 指向哑节点,用于构建新链表。
  3. 初始化进位 carry = 0
  4. 循环条件:l1 不为空l2 不为空carry != 0
  5. 在循环中:
    • l1 的值(如果 l1 不为空,否则为 0)。
    • l2 的值(如果 l2 不为空,否则为 0)。
    • 计算当前和:sum = val1 + val2 + carry
    • 计算新的进位:carry = sum // 10
    • 计算当前位的结果:digit = sum % 10
    • 创建一个新节点,值为 digit,并让 curr.next 指向它,然后 curr 移动到下一个节点。
    • 如果 l1 不为空,l1 后移;如果 l2 不为空,l2 后移。
  6. 循环结束后,返回 dummy.next(哑节点的下一个节点就是结果链表的真正头部)。

举例说明

l1 = [2,4,3]l2 = [5,6,4] 为例:

  • 初始:carry = 0
  • 第 1 位:2 + 5 + 0 = 7,进位 0,结果位 7
  • 第 2 位:4 + 6 + 0 = 10,进位 1,结果位 0
  • 第 3 位:3 + 4 + 1 = 8,进位 0,结果位 8
  • 两个链表都结束,且进位为 0,停止。

结果链表为 [7,0,8],表示数字 807,符合 342 + 465 = 807。


代码框架(供你理解)

def addTwoNumbers(l1, l2):
    dummy = ListNode(0)
    curr = dummy
    carry = 0
    
    while l1 or l2 or carry:
        val1 = l1.val if l1 else 0
        val2 = l2.val if l2 else 0
        total = val1 + val2 + carry
        carry = total // 10
        digit = total % 10
        
        curr.next = ListNode(digit)
        curr = curr.next
        
        if l1:
            l1 = l1.next
        if l2:
            l2 = l2.next
    
    return dummy.next

这样,我们就完成了从题意理解到模拟步骤,再到代码实现的完整讲解。

好的,我们来看 LeetCode 第 2 题「两数相加」 。 题目描述 给你两个 非空 的链表,分别表示两个非负整数。它们的每位数字都是按照 逆序 方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这两个数都不会以 0 开头。 示例 1: 示例 2: 解题思路 1. 理解逆序存储的好处 数字在链表中是逆序存放的(个位在链表头部),这样我们在做加法时,可以从链表头部开始逐位相加,正好符合我们手算加法从低位到高位的顺序。 2. 模拟加法过程 加法规则: 从两个链表的头节点开始,将对应位置的数字相加,再加上 上一位的进位值 。 当前位的和 = l1.val + l2.val + carry 。 当前位的结果值为 和 % 10 ,新的进位值为 和 // 10 。 将结果位的数字作为一个新节点接到结果链表的尾部。 然后指针 l1 、 l2 向后移动一位。 3. 处理链表长度不同的情况 当其中一个链表已经到末尾,而另一个还有节点时,短链表的对应位视为 0。 4. 最后的进位 当两个链表都遍历完后,如果进位值 carry > 0 ,需要在结果链表最后添加一个值为 carry 的节点。 详细步骤 创建一个哑节点(dummy node)作为结果链表的头部,这样可以避免处理结果链表为空的情况。 初始化一个指针 curr 指向哑节点,用于构建新链表。 初始化进位 carry = 0 。 循环条件: l1 不为空 或 l2 不为空 或 carry != 0 。 在循环中: 取 l1 的值(如果 l1 不为空,否则为 0)。 取 l2 的值(如果 l2 不为空,否则为 0)。 计算当前和: sum = val1 + val2 + carry 。 计算新的进位: carry = sum // 10 。 计算当前位的结果: digit = sum % 10 。 创建一个新节点,值为 digit ,并让 curr.next 指向它,然后 curr 移动到下一个节点。 如果 l1 不为空, l1 后移;如果 l2 不为空, l2 后移。 循环结束后,返回 dummy.next (哑节点的下一个节点就是结果链表的真正头部)。 举例说明 以 l1 = [2,4,3] 、 l2 = [5,6,4] 为例: 初始: carry = 0 第 1 位:2 + 5 + 0 = 7,进位 0,结果位 7 第 2 位:4 + 6 + 0 = 10,进位 1,结果位 0 第 3 位:3 + 4 + 1 = 8,进位 0,结果位 8 两个链表都结束,且进位为 0,停止。 结果链表为 [7,0,8] ,表示数字 807,符合 342 + 465 = 807。 代码框架(供你理解) 这样,我们就完成了从题意理解到模拟步骤,再到代码实现的完整讲解。