题目:输入数字 打印从1到最大的n位数 - 图1,按顺序打印出从 打印从1到最大的n位数 - 图2 到最大的 打印从1到最大的n位数 - 图3 位十进制数。比如输入 打印从1到最大的n位数 - 图4,则打印出 打印从1到最大的n位数 - 图5 一直到最大的 打印从1到最大的n位数 - 图6 位数 打印从1到最大的n位数 - 图7

    当你第一次看到这道题目的时候,你可能会觉得很简单,使用一个循环把数打印出来就可以了嘛,所以你可能会写出下面的程序

    1. public static void print1ToMaxOfNDigits(int n) {
    2. int number = 10;
    3. for (int i = 1; i < n; i++) {
    4. number *= 10;
    5. }
    6. for(int i = 1; i < number; i++) {
    7. System.out.println(i);
    8. }
    9. }

    如果你仔细测试的话,你会发现当 打印从1到最大的n位数 - 图8 比较大时,使用 int 类型已经不能表示这么大的数了(即使使用 long 类型整数也无法表示),所以当输入的 n 比较大时,就会发生溢出,这正是这道题考察的关键所在。

    那么解决办法是什么呢? 那就是使用字符串来表示数字,所以这里的关键是使用字符串来模拟加法,这里我们使用自定义的 increment() 方法来进行模拟,该方法的返回值是一个布尔值,来表示是否已经达到了最大值,当字符串数字是 999...999 的时候,如果在继续增加则达到了最大值,这时如果在递增,在最高位就会产生进位,我们根据首位是否有进位来决定返回值,有进位时表示数字达到最大,返回 true,否则返回 false,代码如下

    1. public class Print1ToMaxOfNDigits {
    2. public static void print1ToMaxOfNDigits(int n) {
    3. if (n < 0) {
    4. return;
    5. }
    6. // 使用字符数组来模拟数字
    7. char[] number = new char[n];
    8. // 初始化字符数组
    9. for (int i = 0; i < number.length; i++) {
    10. number[i] = '0';
    11. }
    12. // 当没有进位时,打印数值
    13. while(!increment(number)) {
    14. printNumber(number);
    15. }
    16. }
    17. // 模拟字符串加法的函数
    18. private static boolean increment(char[] number) {
    19. // 首位进位标志
    20. boolean isOverflow = false;
    21. // 是否有进位
    22. int takeOver = 0;
    23. for(int i = number.length - 1; i >= 0; i--) {
    24. // 获得第 n 位的数字表示,takeOver表示前一位的进位
    25. int nNumber = number[i] - '0' + takeOver;
    26. // 如果是个位,则加1
    27. if (i == number.length - 1) {
    28. nNumber++;
    29. }
    30. // 大于等于 10 表示有进位
    31. if (nNumber >= 10) {
    32. // 如果是最高位,则已经达到最大值了,设置首位进位标志为 true
    33. if (i == 0) {
    34. isOverflow = true;
    35. } else {
    36. // 如果不是首位,那么设置有进位
    37. takeOver = 1;
    38. nNumber -= 10;
    39. // 将数字转为字符
    40. number[i] = (char)(nNumber + '0');
    41. }
    42. } else {
    43. // 如果没有进位,则转为字符
    44. number[i] = (char)(nNumber + '0');
    45. // 因为没有进位,所以后续也不会有进位,提前结束循环
    46. break;
    47. }
    48. }
    49. return isOverflow;
    50. }
    51. // 打印字符数组的方法,主要是控制前面的 0 不打印
    52. private static void printNumber(char[] number) {
    53. StringBuilder str = new StringBuilder();
    54. // 是否以 0 开始
    55. boolean beginZero= true;
    56. for(int i = 0; i < number.length; i++) {
    57. if (beginZero && number[i] != '0') {
    58. beginZero = false;
    59. }
    60. // 如果不以0开始了,才把字符添加进去
    61. if (!beginZero) {
    62. str.append(number[i]);
    63. }
    64. }
    65. System.out.println(str);
    66. }
    67. public static void main(String[] args) {
    68. print1ToMaxOfNDigits(2);
    69. }
    70. }