单链表节点定义的Python实现

3 阅读3分钟

单链表节点定义的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

几个容易忽略的细节

  1. l1l2 参数类型是 ListNode | None 所以循环里必须先判断 if l1 再取 .val,不能直接 l1.val,否则空链表会 AttributeError

  2. 进位的处理不能忘 最后 while 条件里的 or carry 很关键。如果只写 while l1 or l2,那么 99 + 1 会得到 00 而不是 100

  3. 哑节点是链表题通用套路 涉及“构建新链表”的题目,用 dummy 可以省去对头节点的特殊判断,代码更统一。

  4. 不要修改原链表 这个解法只读取 l1l2 的值并移动指针,没有改动它们的 valnext,符合题目要求(虽然题目没禁止,但通常不建议改输入)。


复杂度

  • 时间:O(max(m, n)),m、n 为两个链表长度。
  • 空间:O(max(m, n)),结果链表长度最多为 max(m, n) + 1。

直接复制 Solution 类提交即可通过。