题目重点:键是字符串,值可以字符串、列表和字典。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练只接受str/list/dict,dict键必须str;容器插入顺序保留,输出紧凑JSON。
- 有限嵌套、Unicode码点为合法文本;未定义的数值/null类型不擅自扩展,递归深度需限制。
解题路线
- string用双引号包裹,转义quote/backslash和控制字符;// / / 短转义,其余<0x20用四位\u。不能直接str(dict),那是Python语法不是JSON。
- list递归值逗号拼接,dict逐键转义+冒号+递归值。active身份集只记录当前递归路径,检测环;共享但非循环子对象允许重复编码。
- 以标准JSON解析器roundtrip验证,并对同输入与标准序列化输出比较。生产优先成熟库,手写练习必须覆盖空值容器、引号、反斜杠、控制字符和深层引用。
手动走一遍
{"a":["x","y"]}编码结构保持,字符串内换行输出\n而非真实控制换行。x=[];x.append(x)不存在有限树形JSON,拒绝;[shared,shared]无环可重复输出。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
def serialize(value):
active=set()
def string(text):
result=['"']
short={'"':'\\"','\\':'\\\\','\b':'\\b','\f':'\\f','\n':'\\n','\r':'\\r','\t':'\\t'}
for char in text:
if char in short:result.append(short[char])
elif ord(char)<32:result.append('\\u%04x'%ord(char))
else:result.append(char)
result.append('"');return ''.join(result)
def encode(obj):
if type(obj) is str:return string(obj)
if type(obj) not in (list,dict):raise ValueError("string/list/dict only")
if id(obj) in active:raise ValueError("cycle")
active.add(id(obj))
try:
if type(obj) is list:return '['+','.join(encode(x) for x in obj)+']'
if any(type(k) is not str for k in obj):raise ValueError("string keys")
return '{'+','.join(string(k)+':'+encode(v) for k,v in obj.items())+'}'
finally:active.remove(id(obj))
return encode(value)
复杂度
总输出L、深度h,分层字符串join可能反复复制使O(hL)保守时间,辅助O(h+L);可写入流式buffer降低拷贝,仍有Ω(L)输出。
易错点与追问
容易失分的边界
- 只转义双引号而漏反斜杠会改变解析意义。
- 全局seen拒绝共享对象,会误当环。
继续深挖
- 若添加float,NaN/Infinity、−0与精度应怎样规定?
- 超过递归深度时如何改显式stack或限制输入?
