你好,我是林森lsjs
我的Github 地址: sqyCoder (Qiyang) · GitHub
以博文记录成长,用心打磨代码与思维


欢迎来到日耕一题
今天这道是 NOIP 普及组的经典入门题,也是洛谷 P1307。
看着就是 "把数字倒过来" 这么简单,但新手一写就容易踩坑:负号丢了、前导零消不掉、输入 0 直接输出空值。
这道题有两种主流写法:字符串反转法和纯数学法。
我们重点讲更练基本功的数学解法
一、题目完整解读
原题
NOIP 2011 普及组 数字反转
给定一个整数 N,请将该数各个位上数字反转得到一个新数。新数也应满足整数的常见形式,即除非给定的原数为零,否则反转后得到的新数的最高位数字不应为零。
输入格式
一个整数 N。
输出格式
一个整数,表示反转后的新数。
输入输出样例
样例 1:
输入:123
输出:321
样例 2:
输入:-380
输出:-83
样例 3:
输入:0
输出:0
拆解所有要求
- 数位反转:将整数的每一位数字倒序排列
- 符号保留:负数反转后负号仍在最前面,不能丢
- 无前导零:原数末尾的零,反转后不能出现在最高位(原数为 0 除外)
- 零特殊兼容:输入 0 时输出 0,不能输出空值或报错
坑:
Java 中负数直接取模,结果符号和被除数一致,会得到负的数位,直接累加就会出错
末尾多个零的情况(如 1000),反转后要全部消掉,只留 1
数据范围在 int 取值内,无需考虑溢出问题
二、核心知识点
1. 数位拆解:取模 + 除法的经典用法
这是所有数位操作题的核心基本功:
取最后一位:n % 10,可以得到整数最末尾的数字
去掉最后一位:n / 10,整数除法会自动舍弃小数位,相当于砍掉最后一位
循环执行这两步,直到 n 变成 0,就能把所有数位从后往前依次取出来。
2. 符号隔离:规避负数取模坑
如果直接对负数取模,比如 -380 % 10,在 Java 中结果是 -0(实际为 0)
但 -38 % 10 结果是 -8。如果直接把负数位拼进结果,符号就全乱了。
最稳妥的写法是:先单独记录符号,把原数转成正数再处理,最后再把符号乘回去 。
逻辑清晰,完全避开负数取模的坑。
3. 前导零的自动消除原理
很多新手会特意写判断去前导零,其实完全不用。我们用 res = res * 10 + 当前数位 的方式拼接结果,初始 res 为 0。遇到原数末尾的零时,res 始终是 0,相当于自动跳过了这些前置的零,等遇到第一个非零数字后才开始真正累加,天然实现去前导零。
三、分步代码编写 + 逐行讲解
1. 第一步:处理符号与初始化
java
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int sign = 1; // 符号标记,1为正,-1为负
int res = 0; // 反转结果
// 如果是负数,记录符号,把n转成正数处理
if (n < 0) {
sign = -1;
n = -n;
}
先把符号和数值拆开,后面只处理纯数字,逻辑干净很多。
2. 第二步:逐位反转核心循环
java
while (n > 0) {
int digit = n % 10; // 取出当前n的最后一位
res = res * 10 + digit; // 把该位拼到结果的末尾
n = n / 10; // 砍掉n的最后一位
}
**为什么能自动去前导零?**比如 n=380:
- 第一次循环:取出 0,res = 0*10 + 0 = 0
- 第二次循环:取出 8,res = 0*10 + 8 = 8
- 第三次循环:取出 3,res = 8*10 + 3 = 83
开头的零全程没有存在感,自动就被消掉了,完全不用额外写 if 判断。
同时,输入 0 的时候,循环条件n > 0不满足,res 保持 0,天然兼容零的情况,不用单独处理。
3. 第三步:还原符号并输出
java
res *= sign; // 把符号乘回去
System.out.println(res);
sc.close();
正数乘 1 不变,负数乘 - 1 还原负号,一步到位。
四、完整可运行代码
java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int sign = 1;
int res = 0;
// 处理负号,转正数计算
if (n < 0) {
sign = -1;
n = -n;
}
// 逐位反转
while (n > 0) {
int digit = n % 10;
res = res * 10 + digit;
n = n / 10;
}
// 还原符号并输出
System.out.println(res * sign);
sc.close();
}
}
五、执行流程全复盘(重点)
盘就完了,我们拿最容易出错的样例 2 输入-380,一步步跑一遍程序,看清楚每个变量的变化。
程序启动读取 n = -380,sign 初始为 1,res 初始为 0
第一步:符号处理判断 n < 0 → 成立sign = -1,n = -(-380) = 380
第二步:逐位反转循环第一次循环(n=380):
- digit = 380 % 10 = 0
- res = 0 * 10 + 0 = 0
- n = 380 / 10 = 38
第二次循环(n=38):
- digit = 38 % 10 = 8
- res = 0 * 10 + 8 = 8
- n = 38 / 10 = 3
第三次循环(n=3):
- digit = 3 % 10 = 3
- res = 8 * 10 + 3 = 83
- n = 3 / 10 = 0
循环结束(n=0,不满足 n>0)
第三步:输出结果 res * sign = 83 * (-1) = -83输出 -83,和样例完全一致。
再验证样例 3 输入 0:n=0,不进入循环,res=0,sign=1,输出 0,完全正确。
六、拓展:字符串反转写法
如果追求快速实现,也可以用字符串反转的思路,但算法训练更推荐数学解法:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
StringBuilder sb = new StringBuilder(s);
sb.reverse(); // 直接反转字符串
// 处理负号:如果原数是负数,反转后负号在末尾,移到开头
if (s.charAt(0) == '-') {
sb.deleteCharAt(sb.length() - 1); // 删掉末尾的负号
sb.insert(0, '-'); // 插到最前面
}
// 转成int自动去前导零,输出
System.out.println(Integer.parseInt(sb.toString()));
sc.close();
}
}
这种写法依赖 Java 内置方法,适合快速做题,但对数位思维的锻炼不如数学法,面试手写代码优先写数学解法。
七、总结~
核心:用取模取最后一位 + 除法去最后一位的循环完成数位反转,符号单独处理,前导零由累加逻辑自动消除,零值天然兼容。
避坑提醒:
- 不要直接对负数取模,先转正数再处理,避免符号错乱
- 不用特意写判断去前导零,res 从 0 开始累加会自动跳过
- 输入 0 的情况不用单独写分支,循环不执行天然输出 0
一句话:吃透取模 + 除法的数位操作,这一类题全是送分题。
++就到这里,诸位共勉!++
