数字反转(升级版)
按整数、小数、分数、百分数四种格式拆分字符串,分别反转数字部分并按规则去掉多余的零。
OJ: luogu
题目 ID: P1553
难度:普及-
标签:字符串模拟分类讨论python
日期: 2026-07-06 20:42
题意
给出一个数字字符串,它可能是整数、小数、分数或百分数。要求把每个数字部分反转,并按题目规则删除多余的 0。
思路
先按特殊符号判断类型:
| 形式 | 分隔符 | 处理方式 |
|---|---|---|
| 整数 | 无 | 整体反转,再去掉前导零 |
| 小数 | . |
整数部分和小数部分分别反转 |
| 分数 | / |
分子和分母分别反转,不约分 |
| 百分数 | % |
只反转 % 前面的数字 |
去零规则要分清方向:
- 整数部分反转后要去掉前导零,例如
700 -> 7。 - 小数部分反转后要去掉末尾零,例如
084 -> 480 -> 48。 - 如果删除后为空,要保留一个
0。
这题是字符串分类讨论,历史目录中保留了 C++ 暴力文件,但本文以 Python 正解为准,不再创建 brute.py。
Python 知识
/home/rainboy/mycode/hugo-blog/content/program_language/python/input_output_and_strings.md:字符串切片s[::-1]可以反转字符串。/home/rainboy/mycode/hugo-blog/content/program_language/python/oj_input_output_cheatsheet.md:单个字符串输入直接用input().strip()。split(".")、split("/")适合按分隔符拆成两部分。lstrip("0")删除左侧零,rstrip("0")删除右侧零。
代码
python
def reverse_integer_part(text):
result = text[::-1].lstrip("0")
return result if result else "0"
def reverse_decimal_part(text):
result = text[::-1].rstrip("0")
return result if result else "0"
s = input().strip()
if "." in s:
integer_part, decimal_part = s.split(".")
print(reverse_integer_part(integer_part) + "." + reverse_decimal_part(decimal_part))
elif "/" in s:
numerator, denominator = s.split("/")
print(reverse_integer_part(numerator) + "/" + reverse_integer_part(denominator))
elif s.endswith("%"):
print(reverse_integer_part(s[:-1]) + "%")
else:
print(reverse_integer_part(s))Guide 风格代码
cppbook《C++ 快速入门》教学风格的写法(std:: 前缀、i += 1 循环、0 起始下标):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-08-14 14:53
* update_at: 2026-08-14 14:53
*/
#include <iostream>
#include <string>
// 反转"整数部分":从后往前拼出新串,再去掉新串开头多余的 0
std::string reverse_integer_part(std::string s) {
std::string result = "";
int length = (int)s.size();
for (int i = length - 1; i >= 0; i -= 1) {
result += s[i];
}
// 至少保留一位数字,所以 pos + 1 < size 时才继续跳过
int pos = 0;
while (pos + 1 < (int)result.size() && result[pos] == '0') {
pos += 1;
}
return result.substr(pos);
}
// 反转"小数部分":反转后去掉末尾的 0,但至少要保留一个 '0'
std::string reverse_decimal_part(std::string s) {
std::string result = "";
int length = (int)s.size();
for (int i = length - 1; i >= 0; i -= 1) {
result += s[i];
}
while ((int)result.size() > 1 && result[result.size() - 1] == '0') {
result.pop_back();
}
return result;
}
int main() {
std::string s;
std::cin >> s;
std::size_t dot_pos = s.find('.');
std::size_t slash_pos = s.find('/');
std::size_t percent_pos = s.find('%');
if (dot_pos != std::string::npos) {
std::string left = s.substr(0, dot_pos);
std::string right = s.substr(dot_pos + 1);
std::cout << reverse_integer_part(left) << '.' << reverse_decimal_part(right) << '\n';
} else if (slash_pos != std::string::npos) {
// 分数:分子分母分别反转,不带符号,不交换位置
std::string left = s.substr(0, slash_pos);
std::string right = s.substr(slash_pos + 1);
std::cout << reverse_integer_part(left) << '/' << reverse_integer_part(right) << '\n';
} else if (percent_pos != std::string::npos) {
// 百分数:只反转数字部分,百分号留在末尾
std::string number = s.substr(0, percent_pos);
std::cout << reverse_integer_part(number) << "%\n";
} else {
std::cout << reverse_integer_part(s) << '\n';
}
return 0;
}Pythonic 写法
match 按小数/分数/百分号分支反转:
python
def rev_int(text: str) -> str:
return text[::-1].lstrip("0") or "0"
def rev_dec(text: str) -> str:
return text[::-1].rstrip("0") or "0"
s = input().strip()
match s:
case _ if "." in s:
left, right = s.split(".")
print(f"{rev_int(left)}.{rev_dec(right)}")
case _ if "/" in s:
left, right = s.split("/")
print(f"{rev_int(left)}/{rev_int(right)}")
case _ if s.endswith("%"):
print(f"{rev_int(s[:-1])}%")
case _:
print(rev_int(s))复杂度
设输入长度为 n,每次反转和去零都是线性操作,时间复杂度是
总结
本题最容易错的是去零方向。整数部分去前导零,小数部分去末尾零;分数和百分数仍然只处理各自的数字部分。