当前位置:首页 > 技术 > 正文内容

LeetCode 2: 两数相加 - 链表数值计算

访客 技术 2026年6月29日 1

给定两个表示非负整数的非空链表,它们的数字按逆序存储,且每个节点只存储一位数字。请计算这两个数的和,并以相同格式返回结果链表。假设除了数字 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]
    解释: 9999999 + 9999 = 10009998。

约束

  • 链表节点数范围:[1, 100]
  • 节点值范围:[0, 9]
  • 保证列表表示的数字不含前导零。

解法一:迭代模拟

由于链表以逆序存储数字,我们可以直接从链表头部开始逐位相加。在遍历过程中,同时处理进位。对于每一位,计算当前两个节点值之和加上上一位的进位。结果链表的当前节点值为该和对 10 取模,新的进位值为该和除以 10 的整数部分。

如果一个链表比另一个短,可以将其视为在末尾补零。如果在所有位都计算完毕后仍有进位,则在结果链表末尾添加一个新节点来存储这个进位。

此方法的时间复杂度为 O(max(m, n)),其中 m 和 n 是两个链表的长度。空间复杂度为 O(1),因为我们只使用了常数额外的空间。

Python 代码实现

首先定义链表节点结构:


from typing import Optional

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

主函数使用一个伪头节点(dummy)来简化链表构建过程。`cur` 指针用于遍历和构建新链表。


class Solution:
    def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        # dummy 是伪头节点,cur 用于构建新链表
        cur = dummy = ListNode()
        carry = 0  # 初始化进位为0

        # 循环条件:只要 l1、l2 中至少一个非空,或者有进位,就继续
        while l1 or l2 or carry:
            # 获取当前位的值,若链表已遍历完,则值为0
            val1 = l1.val if l1 else 0
            val2 = l2.val if l2 else 0

            # 计算总和,包括进位
            total_sum = val1 + val2 + carry

            # 新节点的数值是总和的个位数
            cur.next = ListNode(total_sum % 10)

            # 更新进位,是总和的十位数
            carry = total_sum // 10

            # 移动 cur 指针到新创建的节点
            cur = cur.next

            # 移动 l1 和 l2 指针到下一个节点(如果存在)
            if l1:
                l1 = l1.next
            if l2:
                l2 = l2.next

        # 返回结果链表的头节点(跳过伪头节点)
        return dummy.next
  

示例运行


# 辅助函数用于打印链表,便于调试
def print_linked_list(head):
    current = head
    result = []
    while current:
        result.append(str(current.val))
        current = current.next
    print("->".join(result))

# 构造示例链表 l1: 2->4->3 (代表 342)
node3 = ListNode(3)
node4 = ListNode(4, node3)
l1_example = ListNode(2, node4)

# 构造示例链表 l2: 5->6->4 (代表 465)
node4_l2 = ListNode(4)
node6_l2 = ListNode(6, node4_l2)
l2_example = ListNode(5, node6_l2)

# 计算结果
solution = Solution()
result_list = solution.addTwoNumbers(l1_example, l2_example)

# 打印结果链表 [7->0->8]
print_linked_list(result_list) # 输出: 7->0->8
  

解法二:递归

这个问题也可以用递归来解决。核心逻辑与迭代类似:计算当前位的和与进位。递归函数接收两个链表的当前节点以及当前的进位值。

递归的基线条件是当两个链表节点都为空时。此时,如果存在进位,则创建一个新的节点表示该进位;否则返回 `None`。

在递归调用时,如果其中一个链表已经遍历完(节点为 `None`),则将其视为 0。为了简化代码,可以确保 `l1` 总是指向较长(或等于)的链表,如果 `l1` 为空但 `l2` 不为空,则交换它们。

递归实现的时间复杂度仍为 O(max(m, n)),但空间复杂度为 O(max(m, n)),因为递归调用栈的深度与最长链表的长度成正比。

Python 代码实现


class SolutionRecursive:
    def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode], carry: int = 0) -> Optional[ListNode]:
        # 基线条件:两个链表都为空
        if not l1 and not l2:
            # 如果有进位,则创建一个进位节点;否则返回 None
            return ListNode(carry) if carry else None

        # 确保 l1 指向较长的链表,简化逻辑
        if not l1:
            l1, l2 = l2, l1

        # 计算当前位的总和(包括进位)
        current_sum = l1.val + (l2.val if l2 else 0) + carry

        # 更新 l1 节点的值为当前位的个位数
        l1.val = current_sum % 10

        # 递归调用处理下一位
        # l1.next 是下一对节点,l2.next 仅在 l2 存在时取
        # carry // 10 是更新后的进位
        l1.next = self.addTwoNumbers(l1.next, l2.next if l2 else None, current_sum // 10)

        # 返回修改后的 l1 链表头
        return l1
  

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。