力扣-2-两数相加

一、题目理解

题目描述

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

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

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

示例

输入:l1 = 2,4,3, l2 = 5,6,4

输出:7,0,8

解释:342 + 465 = 807,逆序存储后结果为 7,0,8。

二、解题思路

这道题的核心是模拟手工加法的过程,关键点如下:

  1. 两个链表逆序存储数字,正好符合"从个位开始相加"的加法逻辑;
  2. 相加时需要处理进位(进位值只能是 0 或 1,因为两个个位数相加最大是 9+9=18,进位1);
  3. 两个链表长度可能不同,需要处理"短链表遍历完但长链表还有剩余"的情况;
  4. 最后如果还有进位(比如 999 + 1 = 1000),需要额外新增一个节点存储进位。

三、Java代码实现

首先定义题目中的链表节点类(力扣会默认提供,无需自己写),然后实现核心逻辑:

java 复制代码
// 链表节点定义(力扣题目中已给出)
class ListNode {
    int val;
    ListNode next;
    ListNode() {}
    ListNode(int val) { this.val = val; }
    ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        // 虚拟头节点(简化链表操作,避免处理头节点为空的情况)
        ListNode dummyHead = new ListNode(0);
        // 遍历指针,用于构建结果链表
        ListNode curr = dummyHead;
        // 进位值,初始为0
        int carry = 0;
        
        // 循环条件:l1未遍历完 或 l2未遍历完 或 还有进位
        while (l1 != null || l2 != null || carry != 0) {
            // 取出当前节点的值,若节点为空则取0
            int val1 = (l1 != null) ? l1.val : 0;
            int val2 = (l2 != null) ? l2.val : 0;
            
            // 计算当前位的和(包含进位)
            int sum = val1 + val2 + carry;
            // 当前位的结果:和对10取余
            int currentVal = sum % 10;
            // 更新进位:和除以10取整(只能是0或1)
            carry = sum / 10;
            
            // 创建新节点,加入结果链表
            curr.next = new ListNode(currentVal);
            // 指针后移
            curr = curr.next;
            
            // 原链表指针后移(非空时)
            if (l1 != null) l1 = l1.next;
            if (l2 != null) l2 = l2.next;
        }
        
        // 虚拟头节点的下一个节点才是结果链表的头
        return dummyHead.next;
    }
}

四、代码关键解析

  1. 虚拟头节点(dummyHead)

    • 为什么用?如果直接用真实头节点,需要额外判断"结果链表是否为空",虚拟头节点可以统一处理所有节点的添加逻辑,最后返回 dummyHead.next 即可。
    • 比如示例中,先创建 dummyHead(0),然后依次添加 7、0、8,最终返回 dummyHead.next 就是 7,0,8。
  2. 循环条件

    • l1 != null || l2 != null || carry != 0:覆盖三种情况:
      • l1还有节点未遍历;
      • l2还有节点未遍历;
      • 两个链表都遍历完,但最后一位相加有进位(如 999 + 1 = 1000)。
  3. 数值处理

    • val1 = l1 != null ? l1.val : 0:短链表遍历完后,后续位用 0 补充(比如 l1=2,4, l2=5,6,4,则 l1 的第三位视为 0);
    • sum = val1 + val2 + carry:必须加上上一位的进位;
    • currentVal = sum % 10:取当前位的结果(如 4+6=10,当前位是 0);
    • carry = sum / 10:更新进位(如 4+6=10,进位是 1)。
  4. 指针移动

    • 结果链表的指针 curr 每次后移,指向新创建的节点;
    • 原链表的指针 l1/l2 只有非空时才后移,避免空指针异常。

五、测试示例

以 l1 = [2,4,3], l2 = [5,6,4] 为例,执行过程:

步骤 val1 val2 carry sum currentVal 结果链表(curr指向)
1 2 5 0 7 7 dummyHead -> 7
2 4 6 0 10 0 dummyHead -> 7 -> 0
3 3 4 1 8 8 dummyHead -> 7 -> 0 -> 8
4 0 0 0 0 - 循环结束
最终返回 dummyHead.next 即 7,0,8,符合预期。

总结

  1. 核心逻辑:模拟手工加法,从个位(链表头)开始相加,处理进位和链表长度不一致的问题;
  2. 关键技巧:使用虚拟头节点简化链表操作,循环条件覆盖"链表未遍历完"和"最后有进位"两种场景;
  3. 边界处理:短链表补 0、最后进位新增节点,避免空指针异常。

这道题是链表的入门经典题,掌握后能理解链表遍历、虚拟头节点、进位处理等核心考点,后续可以尝试优化空间(比如直接在原链表上修改),但上述解法是最易理解、面试中最推荐的写法。

相关推荐
倒头就睡的小比特2 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!2 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼2 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
旖旎夜光2 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark2 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her13 天前
并查集-听课笔记
笔记·算法·并查集
码流子3 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven3 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark3 天前
从算法设计模式看编程思维的抽象能力4
算法
2601_962218613 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法