Medium

题目描述

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

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

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

示例 1:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.

示例 2:

输入:l1 = [0], l2 = [0]
输出:[0]

示例 3:

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

提示:

  • 每个链表中的节点数在范围 [1, 100]
  • 0 <= Node.val <= 9
  • 题目数据保证列表表示的数字不含前导零

解题思路

这道题本质上是在模拟加法运算的过程,由于数字是按逆序存储的,正好可以从最低位开始相加。

思路分析

由于链表存储的是逆序数字,我们可以从两个链表的头部开始同时遍历,逐位相加。关键在于正确处理进位:

  1. 模拟加法:同时遍历两个链表,将对应位置的数字相加,加上之前的进位
  2. 处理进位:每一位的和如果大于等于10,需要向下一位进位
  3. 长度不等:当一个链表遍历完后,另一个链表可能还有剩余节点,需要继续处理
  4. 最后进位:所有节点处理完后,如果还有进位,需要新增一个节点

具体步骤:

  • 使用一个变量 carry 记录进位,初始为0
  • 同时遍历两个链表,计算当前位的和:sum = val1 + val2 + carry
  • 新节点的值为 sum % 10,新的进位为 sum / 10
  • 当其中一个链表为空时,将另一个链表的值作为当前位的值
  • 最后如果还有进位,需要创建新节点

这种方法只需要一次遍历,时间复杂度为O(max(m,n)),空间复杂度为O(max(m,n))(用于存储结果)。

代码实现

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* dummy = new ListNode(0);
        ListNode* curr = dummy;
        int carry = 0;
        
        while (l1 || l2 || carry) {
            int sum = carry;
            if (l1) {
                sum += l1->val;
                l1 = l1->next;
            }
            if (l2) {
                sum += l2->val;
                l2 = l2->next;
            }
            
            curr->next = new ListNode(sum % 10);
            curr = curr->next;
            carry = sum / 10;
        }
        
        return dummy->next;
    }
};
class Solution:
    def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        dummy = ListNode(0)
        curr = dummy
        carry = 0
        
        while l1 or l2 or carry:
            sum_val = carry
            if l1:
                sum_val += l1.val
                l1 = l1.next
            if l2:
                sum_val += l2.val
                l2 = l2.next
            
            curr.next = ListNode(sum_val % 10)
            curr = curr.next
            carry = sum_val // 10
        
        return dummy.next
public class Solution {
    public ListNode AddTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(0);
        ListNode curr = dummy;
        int carry = 0;
        
        while (l1 != null || l2 != null || carry > 0) {
            int sum = carry;
            if (l1 != null) {
                sum += l1.val;
                l1 = l1.next;
            }
            if (l2 != null) {
                sum += l2.val;
                l2 = l2.next;
            }
            
            curr.next = new ListNode(sum % 10);
            curr = curr.next;
            carry = sum / 10;
        }
        
        return dummy.next;
    }
}
var addTwoNumbers = function(l1, l2) {
    let dummy = new ListNode(0);
    let curr = dummy;
    let carry = 0;
    
    while (l1 || l2 || carry) {
        let sum = carry;
        if (l1) {
            sum += l1.val;
            l1 = l1.next;
        }
        if (l2) {
            sum += l2.val;
            l2 = l2.next;
        }
        
        curr.next = new ListNode(sum % 10);
        curr = curr.next;
        carry = Math.floor(sum / 10);
    }
    
    return dummy.next;
};

复杂度分析

复杂度类型分析
时间复杂度O(max(m, n)),其中 m 和 n 分别是两个链表的长度
空间复杂度O(max(m, n)),用于存储结果链表

相关题目