剑指 Offer 每日一题 | 14、打印从1 到最大的 n 位数

705 阅读2分钟

这是我参与8月更文挑战的第25天,活动详情查看:8月更文挑战

一、前言

大家好,本文章属于《剑指 Offer 每日一题》中的系列文章中的第 14 篇。

在该系列文章中我将通过刷题练手的方式来回顾一下数据结构与算法基础,同时也会通过博客的形式来分享自己的刷题历程。如果你刚好也有刷算法题的打算,可以互相鼓励学习。我的算法基础薄弱,希望通过这两三个月内的时间弥补这块的漏洞。本次使用的刷题语言为 Java ,预计后期刷第二遍的时候,会采用 Python 来完成。

二、题目

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

示例1:

输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]

说明:

  • 用返回一个整数列表来代替打印
  • n 为正整数

三、解题

3.1 思路1:常规 for循环

不考虑大数,找到最大值,然后遍历直接输出即可。

3.1.1 代码
    public static int[] printNumbers(int n) {
        int max = 9;
        int tmp=9;
        for (int i = 1; i <n; i++) {
            max=max*10+tmp;
        }
        int[] ints = new int[max];
        for (int i = 0; i <max ; i++) {
            ints[i]=i+1;
        }
        return ints;
    }

public static int[] printNumbers2(int n) {
    int max =1;
    for (int i = 0; i < n; i++) {
        max*=10;
    }
    int[] ints = new int[max-1];
    for (int i = 0; i <max-1 ; i++) {
        ints[i]=i+1;
    }
    return ints;
}
3.1.2 执行效果

image-20210824210805826

3.2 思路2:队列实时维护数组

这题的难点是要考虑大数,而 书本上出这题的目的就是考察对大数的处理,何为大数,假设n=100 的话,这时 int 和long 都无法装载下这些数据,因此,这两种类型都不可以,可以使用 string 来存储大数,然后模拟拼接出所有的数据,循环输出,因为 leetcode 需要返回 int 数组,所以本题还需要将它转为 int 数组,以便满足题意,但实际情况下,直接输出就可以了。

本题的解决想法真的很神奇,动态维护队列输出,也无需考虑书上是否补0 。

可以准备一个队列,先顺序放入 1-9 这几个数,然后还有一个输入的n ,假设 n 是三位数。

  • 先拿出 1,把它放入 数组中,然后判断 1 的长度是否小于3 ,是的,就在后面拼接上 10、11、12...19 这些数据放入队列。
  • 再拿出 2,把它放入数组中,然后判断 2 的长度是否小于 3, 是的,在后面拼接 20、21.. 29 这些数据放入队列。
  • 重复这操作,直到 10进入,发现它还是小于 3位数,继续放入数组,然后在后面拼接 100 到 109
  • 直到最后的 99 的时候拼接最后的 991-999 的数据。
  • 最后队列为空退出。

也就是这种做法是每取出一个数字,我就往后面加上 10个数字,直到位数达到输入的位数的时候才停止加数字,然后到队列为空输出结果。

3.2.1 代码
// 考虑大数
    public static int[] printNumbers3(int n) {
        int[] ans = new int[(int)(Math.pow(10, n)) - 1];
        Queue<String> q = new LinkedList<>();
        //将1~9加入队列
        for (int i = 1; i <= 9; i++){
            q.add(String.valueOf(i));
        }
        int index = 0;
        while (!q.isEmpty()){
            int size = q.size();
            for (int i = 0; i < size; i++) {
                // 拿出一位数字放入队列,然后判断后面是否拼接数字
                String str =q.poll();
                ans[index++]=Integer.parseInt(str);
                if(str.length()<n){
                    // 组装多位数放入队列
                    for(int j=0;j<=9;j++){
                        q.add(str+j);
                    }
                }
            }
        }
        return ans;
    }
3.2.2 执行效果

image-20210824215011088

四、小结

本题的初衷就是考察我们对大数的处理,果然算法题就没有简单的。面试的时候需要明确这种实际上是考察大数问题,而本题中的思路2 的解决方法还是非常巧妙的,找到数据拼接的规律的同时也能顺序输出数组。

今天的刷题就到这了,欢迎点赞评论交流,剑指 Offer 刷题之旅将继续展开!