#2 链表指针 中等

两数相加

在 LeetCode 上查看 ↗

🎧 语音讲解

开车或通勤时可听,跟着思路走一遍

速度

📋 题目描述

给你两个非空的链表,表示两个非负整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。请你将两个数相加,并以相同形式返回一个表示和的链表。

示例 1

输入:l1 = [2,4,3], l2 = [5,6,4](即 342 + 465)
输出:[7,0,8](即 807)

💭 模拟答题者思考

1. 逆序存储正好模拟竖式加法:从个位开始逐位相加。

2. 每位的和 = l1 当前位 + l2 当前位 + 进位;结果位是和对 10 取余,新进位是和整除 10。

3. 用哑结点简化头节点的处理,避免单独判断第一个节点。

4. 循环条件要包含 carry:两链表都走完但还有进位时(如 5+5)也要再建一个节点。

🧠 变量语义(先读这三句再编码)

变量类型语义(三句法)
dummyListNode*定义:哑结点,其 next 永远指向结果链表真正的头
维护:不变,最后返回 dummy.next
更新:不更新
curListNode*定义:结果链表的尾指针
维护:始终指向已建好部分的最后一个节点
更新:每接一个新节点后 cur = cur.next
carryint定义:进位(0 或 1)
维护:等于上一位相加结果整除 10
更新:carry = 当前位和 // 10

⌨️ 落码步骤

1. 建哑结点 dummycur = dummycarry = 0

2. 当 l1l2carry 非空时循环

3. 求和 s = carry + (l1?) + (l2?),同时后移 l1/l2

4. carry, digit = divmod(s, 10),新建节点接到 cur 后,cur 前移

5. 返回 dummy.next

💻 代码实现

# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        dummy = ListNode()   # 哑结点,dummy.next 是结果头
        cur = dummy          # 结果链表尾指针
        carry = 0            # 进位
        while l1 or l2 or carry:
            s = carry
            if l1:
                s += l1.val
                l1 = l1.next
            if l2:
                s += l2.val
                l2 = l2.next
            carry, digit = divmod(s, 10)
            cur.next = ListNode(digit)
            cur = cur.next
        return dummy.next
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode dummy;          // 哑结点
        ListNode* cur = &dummy;  // 结果链表尾指针
        int carry = 0;           // 进位
        while (l1 || l2 || carry) {
            int s = carry;
            if (l1) { s += l1->val; l1 = l1->next; }
            if (l2) { s += l2->val; l2 = l2->next; }
            carry = s / 10;
            cur->next = new ListNode(s % 10);
            cur = cur->next;
        }
        return dummy.next;
    }
};
// 时间 O(max(m,n)),空间 O(max(m,n))

📈 复杂度分析

时间复杂度 O(max(m,n))
空间复杂度 O(max(m,n))

⚠️ 常见坑

循环条件别忘了 carry:最高位相加产生进位时还要补一个节点。

两链表长度可能不同,取值前要判空。

用哑结点避免「结果头节点」的特殊处理,最后返回 dummy.next 而不是 dummy。

🔍 必测边界 Case

Case 1:进位到新位
l1 = [5], l2 = [5] → [0,1](5+5=10)
Case 2:长度不等
l1 = [9,9,9], l2 = [1] → [0,0,0,1]