返回

两数相加:算法高手教你攻破数字迷宫

见解分享

算法迷宫的探险:解开两数相加的数字谜题

在浩瀚的算法世界中,LeetCode 是一座磨砺修行者的圣地。今天,我们将深入 LeetCode 2 这道经典题目的深处,踏上一场解开两数相加数字迷宫的探险之旅。

逐层深入,搭建解谜框架

两数相加看似简单,但其中暗藏玄机。链表的数据结构将数字逆序存储,为我们的解谜之路增添了层层阻碍。为了破解谜题,我们首先搭建解谜框架。

我们定义两个链表 l1l2,它们分别代表需要相加的两个非负整数。为了实现链表相加,我们引入一个虚假的头部节点 dummy,它将最终结果附加到其后方。

踏入迷宫,探索数字奥秘

有了解谜框架,我们便可踏入数字迷宫。算法的核心在于逐位相加,从链表的尾部开始,依次处理每个节点。在相加过程中,我们需要考虑进位的情况,因此引入了一个进位标志 carry

每一步的相加过程如下:

  • 获取 l1l2 当前节点的值,分别为 val1val2
  • 计算 val1val2carry 的和,得到 sum
  • 更新 carrysum 除以 10 的余数。
  • sum 对 10 取模,得到当前节点的数字,并添加到结果链表中。
  • 移动 l1l2 的指针到下一个节点。

走出迷宫,抵达终点

l1l2 都为空时,算法结束。此时,我们检查 carry 是否为 0。如果 carry 为 0,表示相加结果没有进位,算法返回 dummy 的下一个节点,即相加结果的链表。如果 carry 不为 0,则说明相加结果有进位,我们需要在 dummy 的后面创建一个新节点,值为 carry,并将该节点返回作为相加结果。

代码演绎,步步解谜

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

        # 计算和和进位
        sum = val1 + val2 + carry
        carry = sum // 10
        sum = sum % 10

        # 创建新节点并添加到结果链表
        curr.next = ListNode(sum)
        curr = curr.next

        # 移动指针
        l1 = l1.next if l1 else None
        l2 = l2.next if l2 else None

    # 返回结果链表
    return dummy.next

总结与展望,算法之旅永无止境

LeetCode 2:两数相加,这是一道经典的链表操作题目。通过逐位相加和处理进位,我们成功解开了数字迷宫的谜题。算法的精髓在于巧妙的数据结构设计和清晰的逻辑处理。

解谜之路永无止境,算法的海洋浩瀚无垠。愿我们继续探索,在算法的世界中不断发现和创造。

常见问题解答

1. 链表的逆序存储如何影响算法设计?

链表的逆序存储增加了算法的复杂性,因为我们需要从链表的尾部开始相加。因此,算法中需要额外处理指针的移动和结果链表的构建。

2. 进位标志如何确保相加结果的正确性?

进位标志是一个关键的变量,它记录了每一步相加后产生的进位。在后续的相加过程中,进位标志会不断更新,确保算法能够正确计算出最终结果。

3. 虚假头部节点在算法中扮演什么角色?

虚假头部节点是一个巧妙的技巧,它简化了算法的逻辑。虚假头部节点永远指向结果链表的头部,无论结果链表有多长,我们只需要在虚假头部节点的后面追加节点即可。

4. 代码中的 curr 变量有何作用?

curr 变量指向结果链表的尾部,随着算法的进行,curr 会不断移动,在结果链表中追加新的节点。最终,curr 指向的结果链表尾部就是相加结果。

5. 算法的时间复杂度是多少?

算法的时间复杂度为 O(max(m, n)),其中 m 和 n 分别是 l1l2 的长度。这是因为算法需要逐位相加链表中的所有节点。