HJ96. 表示数字
题目描述
将字符串中每一个连续的数字串用符号 * 括起来,其余字符不变。
输入格式
一行字符串(可能含字母、数字等)。
输出格式
处理后的字符串:每个连续数字段前后各加一个 *。
示例
示例 1
输入:
Jkdi234klowe90a3
输出:
Jkdi*234*klowe*90*a*3*
说明:
数字段 234、90、3 分别被 * 括起来。
解题思路
第一步:理解问题本质
要识别所有连续的数字串(\d+),在每个数字串前后插入一个 *,非数字字符原样保留。
第二步:暴力解法(逐字符扫描)
遍历每个字符,判断是否数字,跟踪连续数字段的开始和结束,在段首段尾手动插入 *。
问题:需要维护多个状态(是否在数字段、段起始位置),代码繁琐且易错。
第三步:优化解法(正则替换)
连续数字串用正则 \d+ 一次匹配,替换为 *\1*(\1 引用捕获到的数字串):
result = re.sub(r'(\d+)', r'*\1*', s)
正则引擎自动识别所有连续数字段,代码简洁可靠。
第四步:关于手写扫描
如果不想依赖正则,也可用一次线性扫描:遇到数字时找到连续数字段的结束位置,输出 * + 数字段 + *,然后跳过该段。两种方法都是最优的 O(n),正则实现更简洁。
完整代码实现
本题无可视化步骤:代码里没有可逐帧展示的过程(执行轨迹已经录下来, 但局部变量里找不到推进中的中间状态 —— 比如全篇就是一次正则替换或一次切片)。
import sys
import re
def solve() -> None:
s = sys.stdin.readline().strip()
# 连续数字段用 * 括起来
result = re.sub(r'(\d+)', r'*\1*', s)
print(result)
if __name__ == "__main__":
solve()
示例推演
以示例 1 为例,输入 Jkdi234klowe90a3。
正则 \d+ 依次匹配到三个数字段:
234→ 替换为*234*90→ 替换为*90*3→ 替换为*3*
其余字符 Jkdi、klowe、a 保持不变。
最终结果:Jkdi*234*klowe*90*a*3*。
复杂度分析
| 解法 | 时间复杂度 | 空间复杂度 | 说明 |
|---|---|---|---|
| 逐字符扫描 | O(n) | O(n) | 需维护状态机 |
| 正则替换 | O(n) | O(n) | 简洁可靠 |
n 为字符串长度
易错点总结
1. 连续数字段被拆开
若用 \d 而非 \d+ 逐个替换,每个数字单独加 *,会破坏连续数字段。必须用 \d+ 一次匹配整段。
2. 替换语法写错
捕获组要用括号 (\d+),替换串用 *\1* 引用;漏掉括号或 \1 会导致错误。
3. 空字符串
输入为空时,re.sub 返回空串,直接输出空行即可。
扩展思考
- 正则替换是处理字符串模式匹配的利器,可扩展处理连续字母、连续标点等类似需求。
- 若要求在每个数字段内部的每个数字也加
*,则属于另一个问题,需用\d逐个替换。