题目:输入数字
,按顺序打印出从
到最大的
位十进制数。比如输入
,则打印出
一直到最大的
位数
。
当你第一次看到这道题目的时候,你可能会觉得很简单,使用一个循环把数打印出来就可以了嘛,所以你可能会写出下面的程序
public static void print1ToMaxOfNDigits(int n) {
int number = 10;
for (int i = 1; i < n; i++) {
number *= 10;
}
for(int i = 1; i < number; i++) {
System.out.println(i);
}
}
如果你仔细测试的话,你会发现当 比较大时,使用
int
类型已经不能表示这么大的数了(即使使用 long
类型整数也无法表示),所以当输入的 n
比较大时,就会发生溢出,这正是这道题考察的关键所在。
那么解决办法是什么呢? 那就是使用字符串来表示数字,所以这里的关键是使用字符串来模拟加法,这里我们使用自定义的 increment()
方法来进行模拟,该方法的返回值是一个布尔值,来表示是否已经达到了最大值,当字符串数字是 999...999
的时候,如果在继续增加则达到了最大值,这时如果在递增,在最高位就会产生进位,我们根据首位是否有进位来决定返回值,有进位时表示数字达到最大,返回 true
,否则返回 false
,代码如下
public class Print1ToMaxOfNDigits {
public static void print1ToMaxOfNDigits(int n) {
if (n < 0) {
return;
}
// 使用字符数组来模拟数字
char[] number = new char[n];
// 初始化字符数组
for (int i = 0; i < number.length; i++) {
number[i] = '0';
}
// 当没有进位时,打印数值
while(!increment(number)) {
printNumber(number);
}
}
// 模拟字符串加法的函数
private static boolean increment(char[] number) {
// 首位进位标志
boolean isOverflow = false;
// 是否有进位
int takeOver = 0;
for(int i = number.length - 1; i >= 0; i--) {
// 获得第 n 位的数字表示,takeOver表示前一位的进位
int nNumber = number[i] - '0' + takeOver;
// 如果是个位,则加1
if (i == number.length - 1) {
nNumber++;
}
// 大于等于 10 表示有进位
if (nNumber >= 10) {
// 如果是最高位,则已经达到最大值了,设置首位进位标志为 true
if (i == 0) {
isOverflow = true;
} else {
// 如果不是首位,那么设置有进位
takeOver = 1;
nNumber -= 10;
// 将数字转为字符
number[i] = (char)(nNumber + '0');
}
} else {
// 如果没有进位,则转为字符
number[i] = (char)(nNumber + '0');
// 因为没有进位,所以后续也不会有进位,提前结束循环
break;
}
}
return isOverflow;
}
// 打印字符数组的方法,主要是控制前面的 0 不打印
private static void printNumber(char[] number) {
StringBuilder str = new StringBuilder();
// 是否以 0 开始
boolean beginZero= true;
for(int i = 0; i < number.length; i++) {
if (beginZero && number[i] != '0') {
beginZero = false;
}
// 如果不以0开始了,才把字符添加进去
if (!beginZero) {
str.append(number[i]);
}
}
System.out.println(str);
}
public static void main(String[] args) {
print1ToMaxOfNDigits(2);
}
}