题目重点:手写 IPv4 字符串检查,围绕四段十进制、非法字符、前导零和 255 边界设计测试;区分题目明确规则与训练补充。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练版要求恰好四段,由英文点分隔;每段是 1–3 个 ASCII 十进制数字,数值 0..255。
- 单个 '0' 合法,多位段不得以 0 开头;空字符串、空段、符号、空格、非 ASCII 数字都拒绝。
- 只做语法与段值校验,不判断保留地址、广播地址、可路由性或 CIDR。
解题路线
- 按 '.' 分割并验证恰好得到四段;若写 C++ 无现成 split,可逐字符扫描,遇点提交当前段。
- 每段先检查非空、ASCII 数字和前导零,再逐位构造数值并检查 ≤255;最多三位可提前拒绝,避免巨大输入转换。
- 训练代码用 Python split 简洁展示约束;C++ 面试时特别要处理连续点、首尾点和最后一段提交。
- 校验目标是 IPv4 文本表示,不是 DNS 地址解析,也不应自动去空格或允许 '+1'。
手动走一遍
192.168.0.1 四段都合法;192.168.00.1 的第三段有前导零;256.1.1.1 越界;1..2.3 含空段;1.2.3 少一段。题目只明言前导零/范围,其他返回行为是本训练版明确化的语法约定。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
def valid_ipv4(text: str) -> bool:
"""Four ASCII-decimal octets; zero allowed only as the single digit '0'."""
parts = text.split(".")
if len(parts) != 4:
return False
for part in parts:
if not part or (len(part) > 1 and part[0] == "0"):
return False
if any(char < "0" or char > "9" for char in part):
return False
if len(part) > 3 or int(part) > 255:
return False
return True
if __name__ == "__main__":
assert valid_ipv4("192.168.0.1")
assert not valid_ipv4("192.168.00.1")
复杂度
输入长度 L,split 与逐字符检查 O(L) 时间、O(L) 空间;手写流式解析只保留当前段和值,可降 O(1) 工作空间。
易错点与追问
容易失分的边界
- 直接 int('') 或接受空段。
- Python str.isdigit() 也认可一些非 ASCII 数字,和常见 IPv4 文本语法不一致。
- 把字符串长度 3 当充分条件而忘记 256..999 越界。
- 拒绝单个 0,误解‘排除 0 开头的数字’。
- 凭题目推断面试官问了网段合法性或保留地址;它只记录普通字符串校验。
继续深挖
- 若允许 leading zeros,多个文本地址是否应归一成同一数值地址?
- 给定 IPv4/CIDR,校验前缀长度并计算网络地址怎样做?
- 如何设计 C++ 单遍解析避免 split 分配?
