• 从零学算法(LCR 135)


    实现一个十进制数字报数程序,请按照数字从小到大的顺序返回一个整数数列,该数列从数字 1 开始,到最大的正整数 cnt 位数字结束。
    示例 1:
    输入:cnt = 2
    输出:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99]

    • 很容易想到的是,cnt 为几代表从 1 到 10的cnt次-1,所以可以直接循环暴力
    •   public int[] countNumbers(int cnt) {
            int end = (int)Math.pow(10,cnt)-1;
            ans = new int[end];
            for(int i=0;i<end;i++){
                ans[i] = i+1;
            }
            return ans;
        }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    • 他人题解:那这题肯定不是为了考察你对循环的使用吧,你用 short/int/long 存储数字,都终归有个存储范围,因此表示大数时考虑使用字符串类型。使用字符串的话,其实你会发现这就是 cnt 位的 0-9 的全排列问题。由于每位都是一样的操作,所以我们基于分治的思想递归生成结果。即遍历 0-9 ,先固定最高位,次高位,…最后固定最后一位,最后一遍遍历到下个数,然后回溯到次低位遍历到下个数…比如 cnt 为 3,先固定第一位 0,然后固定第二位 0,然后第三位的 0,得到 000,继续遍历最后一位,得到 001,002…009,最后一位遍历结束,向上回溯遍历第二位得到 010,011…,初步编写全排列代码如下
    •   StringBuilder res;
        int count = 0, cnt;
        char[] num, loop = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
        public String countNumbers(int cnt) {
            this.cnt = cnt;
            res = new StringBuilder(); // 数字字符串集
            num = new char[cnt]; // 定义长度为 cnt 的字符列表
            dfs(0); // 开启全排列递归
            res.deleteCharAt(res.length() - 1); // 删除最后多余的逗号
            return res.toString(); // 转化为字符串并返回
        }
        void dfs(int x) {
            if(x == cnt) { // 终止条件:已固定完所有位
                res.append(String.valueOf(num) + ","); // 拼接 num 并添加至 res 尾部,使用逗号隔开
                return;
            }
            for(char i : loop) { // 遍历 ‘0‘ - ’9‘
                num[x] = i; // 固定第 x 位为 i
                dfs(x + 1); // 开启固定第 x + 1 位
            }
        }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
    • 这里可以生成我们要的结果,但是会多出比如 000,010,020 这种高位补 0 的字符串,因此第一步我们先去掉高位的 0,我们用一个 start 表示结果字符串 str 的左边界,比如 cnt 为 3,最开始的 000-009,其实我们只要取第 3 位即可,之后的 010-099,其实我们只要取第二位到第三位,start 对应的分别是 str[2:],以及 str[1:],即左边界 start 随着临界值 9,99,999… 不断减少 1,初始为 cnt-1(看代码能看懂),为了不断更新 start,我们就需要用一个变量比如 nine 来表示当前数包含的 9 的数量 ,这就能表示是否来到了临界值。观察后我们会得到如果 cnt-start==nine(cnt-start 你可以看做几位数,比如等于 1 为表示一位数,等于 2 则为表示两位数,nine 就是上面说的,表示增加位数的临界点),start 就需要减 1 了。你可以理解为比如当 nine 为 1,即之后的最大值开始为两位数了,start 每减少 1 就是能表示的数的最多位 +1,所以我们所能表示的就从最开始的一位数成了两位数。
    • 还剩最后一个问题,即题目要求从 1 开始,而我们是从 0 开始,很简单,比如最开始的 000,我们得到了一位数 0,为 0 我们就跳过呗
    • 这里的 nine 的获取别忘了恢复
    •   int[] res;
        // nine:当前数包含的 9 的个数
        int nine = 0, count = 0, start, cnt;
        // num:表示结果字符串的 char 数组
        char[] num, loop = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
        public int[] countNumbers(int cnt) {
            this.cnt = cnt;
            res = new int[(int)Math.pow(10, cnt) - 1];
            num = new char[cnt];
            start = cnt - 1;
            dfs(0);
            return res;
        }
        void dfs(int x) {
            if(x == cnt) {
                String s = String.valueOf(num).substring(start);
                if(!s.equals("0")) res[count++] = Integer.parseInt(s);
                if(cnt - start == nine) start--;
                return;
            }
            for(char i : loop) {
                if(i == '9') nine++;
                num[x] = i;
                dfs(x + 1);
            }
            // 回溯后没 9 就给我恢复了,有的话我自会加
            nine--;
        }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
  • 相关阅读:
    linux性能优化--性能追踪建议
    DocuWare 文档管理软件:基于云的解决方案
    使用 PyTorch 的计算机视觉简介 (4/6)
    什么情况下mysql 会索引失效?
    LCR 012.寻找数组的中心下标
    【多媒体文件格式】AVI、WAV、RIFF
    Android ImageView详解
    泰拉瑞亚EasyBuildMod便捷建造模组开发详细过程
    AR导览小程序开发方案
    [附源码]SSM计算机毕业设计教学辅助系统JAVA
  • 原文地址:https://blog.csdn.net/m0_53256503/article/details/134005689