Python · 2 分钟阅读
Python:将链表转换为字符串
目录
把单链表 val -> val -> val -> ... 序列化为字符串是常见操作,比如把一道
LeetCode 链表题的结果打印或比较。本章讨论不同方向、不同需求下的写法。
链表约定:头节点 = 数字的最低位(与
02.两数相加题目一致)。
1. 节点定义
from __future__ import annotations
from typing import Optional, Iterable
class ListNode:
def __init__(self, val: int = 0, next: Optional["ListNode"] = None) -> None:
self.val = val
self.next = next
2. 拼接出字符串
2.1 头是低位 → 数字字符串
def list_to_number_str(head: Optional[ListNode]) -> str:
"""7 -> 0 -> 8 → '807'"""
parts: list[str] = []
while head:
parts.append(str(head.val))
head = head.next
return "".join(reversed(parts))
要点:
- 把每个
val转字符串、放入列表; reversed后join—— 一次性分配好结果串,比反复s = str(x) + s
快很多。- 空链表返回
""。
2.2 头是高位 → 顺序字符串
def list_to_str(head: Optional[ListNode]) -> str:
"""'a' -> 'b' -> 'c' → 'abc'"""
return "".join(str(node.val) for node in iter_list(head))
def iter_list(head: Optional[ListNode]) -> Iterable[ListNode]:
while head:
yield head
head = head.next
3. 完整可运行示例
def build(values: Iterable[int]) -> Optional[ListNode]:
dummy = ListNode(0)
cur = dummy
for v in values:
cur.next = ListNode(v)
cur = cur.next
return dummy.next
if __name__ == "__main__":
# 例 1:头是低位(7 -> 0 -> 8 → 807)
n = build([7, 0, 8])
assert list_to_number_str(n) == "807"
# 例 2:头是高位
n = build([1, 2, 3])
assert list_to_str(n) == "123"
# 例 3:空链表
assert list_to_number_str(None) == ""
assert list_to_str(None) == ""
# 例 4:负数 / 多位 val
n = ListNode(12, ListNode(34)) # 12 -> 34
assert list_to_str(n) == "1234"
print("ok")
如果链表的
val是两位以上数字,先决定 拼接规则 是“直接连接”(12, 34→
"1234")还是“按数值格式化”(12, 34→"12 34")。本文例子使用前者。
4. 性能 / 复杂度
| 实现 | 时间 | 空间(除输入外) |
|---|---|---|
s = str(x) + s(头低位) |
O(n²) | O(n) |
list + reversed + join |
O(n) | O(n) |
list + 直接 join(头高位) |
O(n) | O(n) |
Python 的
str是不可变的,反复s = str(x) + s会 每次创建新字符串,
长度 n 的链表累计 O(n²) 操作。join一次到位。
5. 工具函数:转回链表 / 转列表
def list_to_pylist(head: Optional[ListNode]) -> list[int]:
"""转成 Python 列表(从头到尾的顺序)。"""
out: list[int] = []
while head:
out.append(head.val)
head = head.next
return out
def str_to_list(s: str) -> Optional[ListNode]:
"""把字符串每个字符转成 ListNode(头是高位)。"""
if not s:
return None
head = ListNode(int(s[0]))
cur = head
for ch in s[1:]:
cur.next = ListNode(int(ch))
cur = cur.next
return head
6. 与反序列化的对比:复杂度提示
链表 ↔ 字符串互转都是 O(n),因为要遍历每个节点。但如果加上“验证这是合法数字”
(例如不能有前导零),单次遍历就够,不必再走一遍。
def is_valid_number_str(head: Optional[ListNode]) -> bool:
s = list_to_number_str(head)
if not s:
return False
return s.lstrip("0") == s or s == "0"
7. 常见错误
- 空指针没处理:第一个节点就为
None时函数必须能直接返回。 - 混淆高低位:一定要明确“头是高位还是低位”,否则结果整段颠倒。
- 数字位数 ≠ 字符位数:上面
val=12的例子要特别留意,要么规定 val
是 0~9,要么明确格式化规则。 - 拼接性能:见第 4 节。
str(x) + s写法在 n 大时会显著变慢。