美文网首页
幸运数字问题 —— Java实现

幸运数字问题 —— Java实现

作者: 进击的NULL | 来源:发表于2019-01-17 12:32 被阅读0次

    题目描述

    小雅同学认为6,8是她的幸运数字,而其他数字均不是,一个幸运数是指在十进制表示下只含有幸运数字的数。给定你一个区间(a,b)a和b之间(其中包括a和b幸)运数的个数。

    输入描述

    输入两个整数a和b,a的取值范围在1和1000000000之间(其中包括1和1000000000),b的取值范围在a和1000000000之间(其中包括a和1000000000)。

    输出描述

    返回a和b之间的幸运数个数,如果入参不合法,请输出-1

    时间、空间要求

    时间限制:1秒 空间限制:32768K

    示例

    输入

    1 10

    输出

    2

    说明

    6,8,6666,88888,6668888,68686688均为幸运数字,当a=1,b=10函数返回值为2。

    解题思路

    首先一看数量级,如果用遍历,然后挨个判断显然是不行的,肯定会超出时间限制,通过数学枚举找规律发现:这就是一个全排列问题,100 - 1000 的幸运数的在1- 10的所有幸运数的基础上跟‘6’和‘8’全排一下组成百位级别的幸运数,以此类推。换句话说,每个区间内的幸运数是已知的(总共2^ i个,i为数的位数,比如个位数(i == 1),就是从‘6’、 ‘8’中选i个数全排列组成一个整数),怎样得到每个区间的幸运数n?就是通过上一个区间迭代得到。这样将一个时间复杂度为O(N)(而且要去判断该数是否是幸运数,这个复杂度系数应该会很大!!!)变为了复杂度O(logN).

    代码

    package string;
    
    /**
     * 幸运数字
     * 最佳时间43ms,时间复杂度O(logN)
     * 特别注意的是,某几个+=操作,通过寄存器简单的加减指令,可以优化20ms左右,这也是让我更加注重让自己的代码尽量清爽简洁,以便于提升!
     */
    import java.util.Scanner;
    public class ImprovedLuckyNum {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int a = sc.nextInt();
            int b = sc.nextInt();
            int INF = 1000000000;
            int[] before = new int[512];
            int[] after = new int[512];
            if (a < 1 || a > INF || a > b) {
                System.out.println(-1);
            } else {
                int sum = 0;
                for (int i = 1; i <= 9; i++) {  
                    int length = (int)Math.pow(2, i); // 这个区段有多少个这样的数
                    // 判断超过范围即可退出了
                    if (Math.pow(10, i) > b) {
                        break;
                    }
                    if (i == 1) {
                        after[0] = 6;
                        after[1] = 8;
                    } else {
                        int b_l = (int)Math.pow(2, i - 1); // 表示before数组的包含有效值的长度
                        for (int k = 0; k < b_l; k++) {
                            after[k] = before[k] * 10 + 6;
                            after[k + b_l] = before[k] * 10 + 8;
                        }
                    }
                    
                    // 寻找合适的数
                    for (int j = 0; j < length; j++) {
                        if (after[j] >= a && b >= after[j]) {
                            sum++;
                        }
                        // 记得更新before数组,用于迭代
                        before[j] = after[j];
    //                  after[j] = INF + 1;
                    }
                }
                System.out.println(sum);
            }
        }
    }
    

    运行结果

    时间在50ms左右,空间使用在10000k左右,基本上快赶上C/C++的时间了(C/ C++时间大概在30ms左右)
    另外:减少一些寄存器指令也可以起到一定的优化效果,10ms左右

    相关文章

      网友评论

          本文标题:幸运数字问题 —— Java实现

          本文链接:https://www.haomeiwen.com/subject/vdfidqtx.html