跳至主要內容

打印从1到最大的n位数

soulballad算法剑指Offer剑指Offer约 912 字大约 3 分钟

题目:

输入数字n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出1、2、3、一直到最大的 3位数 999。

分析:看到这道题很容易想到的办法是,先求出最大的n位数,然后用一个循环打印出所有数。

public static void printNumWithMax(int n) {

    long num = 1;
    // 利用循环计算出 (n+1) 位十进制数
    for (int i = 0; i < n; i++) {
        num *= 10;
    }

    // 循环打印(n+1)位十进制数的前一位,即是n位最大数
    for (int i = 1; i < num; i++) {
        System.out.println(i);
    }
}

上面的方法虽然打印出了所有数字,但是没有考虑边界问题,题目没有说明 n 的取值范围,所以不适合用 int保存,用long类型也可能会越界,所以要考虑使用字符串来保存数字。

在字符串表达数字上模拟加法,我们首先设置是否溢出标识,是否进位标识,以及取得字符数组长度,遍历这个字符数组,在末尾进行+1操作,如果末尾字符在+1后变为不小于10的数字,我们将末尾减去10加上‘0’字符赋值为末位,进位标识设置为1,在循环次位时+1,然后再判断是否为不小于10,是的话重复上面的步骤。直到判断高位是不是不小于10,是的话字符数组溢出;如果末尾字符在+1后是小于10的数字,直接加上‘0’赋值给末尾,跳出当前循环,返回没有溢出。

在字符串表达的数字打印出来方法时,没有什么特别,直接利用for循环遍历输出字符数组,但是要从高位第一个不是0的开始输出。

private static boolean incrementNumber(char[] number) {
    boolean isOverflow = false; //判断是否溢出
    int nTakeOver = 0; //判断是否进位
    int nLength = number.length;
    for (int i = nLength - 1; i >= 0; --i) {
        int nSum = number[i] - '0' + nTakeOver; //取到第i位的字符转换为数字 +进位符
        if (i == nLength - 1) { //末尾自加1
            ++nSum;
        }
        if (nSum >= 10) {
            if (i == 0) {
                isOverflow = true;
            } else {
                nSum -= 10;
                nTakeOver = 1;
                number[i] = (char) ('0' + nSum);
            }
        } else {
            number[i] = (char) (nSum + '0');
            break;
        }
    }
    return isOverflow;
}

private static void printNumber(char[] number) {
    boolean isBeginning0 = true;
    int nLength = number.length;
    for (int i = 0; i < nLength; ++i) {
        if (isBeginning0 && number[i] != '0') {
            isBeginning0 = false;
        }
        if (!isBeginning0) {
            System.out.print(number[i]);
        }
    }
    System.out.println();
}

把问题转化为数字排列的解法,使用递归可以使代码简洁明了。即:如果在所有的数字前面补0的话,就会发现n位所有的十进制数其实就是n个从0到9的全排列。也就是说,我们把数字的每一位都从0到9排列一遍,就得到了所有的十进制数。在打印时,数字排在前面的0不打印。

全排列递归实现最容易。数字的每一位都可能是0到9的一个数,然后设置下一位。递归结束的条件就是我们已经设置了数字的最后一位。

public static void printToMaxByCursive(int n) {
    if (n <= 0) {
        System.out.println("输入的n没有意义");
        return;
    }
    char number[] = new char[n];
    for (int i = 0; i < number.length; i++) {
        number[i] = '0';
    }
    for (int i = 0; i < 10; ++i) {
        number[0] = (char) (i + '0');
        printToMaxOfNDigitsRecursively(number, n, 0);
    }
}


//利用递归实现1到最大的n位数的全排列
private static void printToMaxOfNDigitsRecursively(char[] number, int n, int index) {
    if(index == n - 1){
        printNumber(number);
        return;
    }
    for (int i = 0; i < 10; ++i) {
        number[index + 1] = (char) (i + '0');
        printToMaxOfNDigitsRecursively(number, n, index + 1);
    }
}
上次编辑于:
贡献者: soulballad