解题思路:
这题乍一看看上去还是比较容易,我们很自然的就想到先求出那个最大的n位数,然后在从1开始打印出来即可。这种解法存在一个致命的缺点,当n较大是,所需打印的数有很大部分超过了整形所能表示的范围。在java中,整形用4字节表示,所能表示的整数范围是-2147483648~2147483647。所能表示的数字也顶多是10位,因此当n较大时,我们需要转换思路。既然不能用整形来表示数字,那么可以想到用字符数组来存储数字的每一位。
从整体上来看,需要做两件事:(1)对字符数组代表的数字进行加1操作;(2)对加1后的字符数组进行打印,按照常规方式,需去除前面多余的'0'。具体步骤详见代码注释
/**打印1到最大的n位数
*
*/
public class Solution {
public static void print1ToMaxOfDigits(int n) {
if (n <= 0) {
System.out.println("Invalid Input");
}
//创建一个具有n个元素的字符数组,并设置初始值都为字符'0'
char[] number = new char[n];
for (int i = 0; i < number.length ; i++) {
number[i] = '0';
}
while (!incrementIsOverflow(number)) {
//如果+1后为越界,则将其打印出来
printNumber(number);
}
}
public static boolean incrementIsOverflow(char[] number) {
//该标志位用于判断当前字符数组是否达到最大值,如果达到最大值,则停止继续+1的操作
boolean isOverFlow = false;
//进位符,表示在+1的过程中所产生的进位,开始为0;
int nTakeOver = 0;
//从字符数组的最后一位开始,进行+1操作,因为+1是在个位发生
for (int i = number.length - 1; i >= 0; i--) {
//取到当前数组的第i位上的数字字符
char digit = number[i];
//计算出当前字符所对应的数字加上进位后的结果
//当前字符对应的数字用字符-'0'来表示
int nSum = digit - '0' + nTakeOver;
if (i == number.length - 1) {
//如果当前位是数组的末尾,即数字的个位,则数值需要加1
nSum++;
}
//判断当前字符对应的数字是否大于等于10
if (nSum >= 10) {
//如果当前字符对应的数字大于等于10
if (i == 0) {
//如果是最高位的数字大于等于10,则超过n位的最大整数
isOverFlow = true;
} else {
//除最高位以外的其他位字符对应的数字大于等于10
//产生进位
nTakeOver = 1;
nSum = nSum - 10;
//更新number[i]的数字字符
number[i] = (char) (nSum + '0');
}
} else {
//如果当前字符对应的数字小于10,即不会产生进位
//只需更新number[i]对应的数字字符
number[i] = (char) (nSum + '0');
//跳出循环,因为i之前的数字也不可能变,无需循环
break;
}
}
return isOverFlow;
}
/**
* 对每次进行+1操作后的数字进行打印,按照常规来打印
* @param number
*/
public static void printNumber(char[] number) {
int i;
//需要定位到数组中第一个非0的数字
for (i = 0; i < number.length ; i++) {
if (number[i] != '0') {
//如果找到第一个不为0的字符,跳出循环
break;
}
}
//从i处开始打印字符数组中的数字
while (i < number.length) {
System.out.print(number[i]);
i++;
}
//没打印完一个数字,下次从新行开始打印
System.out.println();
}
}