单链表节点定义的Python实现
完整代码
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def addTwoNumbers(self, l1: ListNode | None, l2: ListNode | None) -> ListNode | None:
dummy = ListNode(0) # 哑节点,方便构建结果链表
cur = dummy # 当前结果链表的尾节点
carry = 0 # 进位
# 只要还有节点,或者还有进位,就继续
while l1 or l2 or carry:
v1 = l1.val if l1 else 0
v2 = l2.val if l2 else 0
total = v1 + v2 + carry
carry = total // 10
cur.next = ListNode(total % 10)
cur = cur.next
if l1:
l1 = l1.next
if l2:
l2 = l2.next
return dummy.next
逐行说明
dummy = ListNode(0)
cur = dummy
carry = 0
dummy是哑节点,值随便填 0,它的next才是真正的结果头节点。cur始终指向结果链表的最后一个节点,方便往后接新节点。carry记录进位,初始为 0。
while l1 or l2 or carry:
三个条件满足任一就继续:
l1还有节点没处理l2还有节点没处理- 还有进位没处理完(比如
99 + 1,两个链表都空了但 carry=1)
v1 = l1.val if l1 else 0
v2 = l2.val if l2 else 0
如果某个链表已经走完,当前位就当作 0。比如 342 + 45,第二趟时 l2 已空,v2 取 0。
total = v1 + v2 + carry
carry = total // 10
cur.next = ListNode(total % 10)
cur = cur.next
total是当前位三数之和(可能 ≥ 10)。total // 10是新的进位。total % 10是当前位保留的数字。- 新建节点接到
cur后面,然后cur后移。
if l1:
l1 = l1.next
if l2:
l2 = l2.next
分别移动两个指针,已经为 None 的不用动。
return dummy.next
dummy 本身是辅助节点,真正的结果从 dummy.next 开始。
本地测试用(可选)
LeetCode 上不需要这些,但如果你想在本地跑,可以加上:
def build_list(nums):
dummy = ListNode(0)
cur = dummy
for n in nums:
cur.next = ListNode(n)
cur = cur.next
return dummy.next
def print_list(head):
vals = []
while head:
vals.append(str(head.val))
head = head.next
print(" -> ".join(vals))
if __name__ == "__main__":
sol = Solution()
# 342 + 465 = 807
l1 = build_list([2, 4, 3])
l2 = build_list([5, 6, 4])
print_list(sol.addTwoNumbers(l1, l2)) # 7 -> 0 -> 8
# 0 + 0 = 0
print_list(sol.addTwoNumbers(build_list([0]), build_list([0]))) # 0
# 9999999 + 9999 = 10009998
print_list(sol.addTwoNumbers(
build_list([9, 9, 9, 9, 9, 9, 9]),
build_list([9, 9, 9, 9])
)) # 8 -> 9 -> 9 -> 9 -> 0 -> 0 -> 0 -> 1
几个容易忽略的细节
-
l1和l2参数类型是ListNode | None所以循环里必须先判断if l1再取.val,不能直接l1.val,否则空链表会AttributeError。 -
进位的处理不能忘 最后
while条件里的or carry很关键。如果只写while l1 or l2,那么99 + 1会得到00而不是100。 -
哑节点是链表题通用套路 涉及“构建新链表”的题目,用
dummy可以省去对头节点的特殊判断,代码更统一。 -
不要修改原链表 这个解法只读取
l1、l2的值并移动指针,没有改动它们的val或next,符合题目要求(虽然题目没禁止,但通常不建议改输入)。
复杂度
- 时间:O(max(m, n)),m、n 为两个链表长度。
- 空间:O(max(m, n)),结果链表长度最多为 max(m, n) + 1。
直接复制 Solution 类提交即可通过。