求出不超过n的幸运数

来源:互联网 发布:微电影制作软件 编辑:程序博客网 时间:2024/05/18 18:42

题目描述:

对于某一个数m,如果它只包含数字4或者7(如44,47,77),我们称之为幸运数。现在输入一个自然数x,求出不超过x的幸运数的个数。
注意:结果可能非常大,请将答案除10^9+7取余数。

思路一:

1. 引入队列queue,开始时将4,7入队。2. while(queue.peek() <= x)   则将queue头部元素top出队,并且将top*10+4和top*10+7入队   count++;   这样形成数字序列:4,7,44,47,74,77,444,447...3. 当2跳出循环时,return count;

算法有点思路简单,但是每出队一个数,将入队两个数,空间复杂度高。

思路二:
可以发现:

不考虑x数值大小,x位数与幸运数的个数关系如下:位数   幸运数个数      可能值 1       2           472       2+4=6       47444774773       2+4+8=14    4744477477444...,777...n       2+4+8+...+2^n = 2^(n+1)-2

尝试用动态规划求解。
这里写图片描述

1. 如果x有len位数,那么对于1~(m-1,m)~len而言,假定m-1处有pre个幸运数,m处有cur个幸运数,如上图所示。2. 那么针对Xm数值,分类考虑:if (Xm < 4)    cur = 2^m - 2;else if (Xm == 4)    /**    *比如:Xm=4,XmXm-1Xm-2...X1    *(1)4Xm-1Xm-2...X1为幸运数的情况(与Xm-1Xm-2...X1为幸运数的情况相同);pre    *(2)m-1位数中幸运数的个数:2^m - 2    *(3)将(1)和(2)合并,需要注意的是,两者有一部分幸运数是相同的,因此需要减去相同幸运数的个数2^(m-1) - 2    */    cur = pre - [2^(m-1) - 2] + [2^m - 2]    cur = pre + 2^(m-1);else if (4 < Xm && Xm < 7)    cur = pre + [2^(m+1) - 2] - 4    /**    *同 Xm == 4的情况类似。    *比如:Xm=7,XmXm-1Xm-2...X1    *(1)7Xm-1Xm-2...X1为幸运数的情况(与Xm-1Xm-2...X1为幸运数的情况相同);pre    *(2)499...9(m-1个9)内幸运数的个数:2 *(2^m - 2)- [2^(m-1) - 2]    *(3)将(1)和(2)合并,需要注意的是,两者有一部分幸运数是相同的,因此需要减去相同幸运数的个数2^(m-1) - 2    */else if (Xm == 7)    cur = pre + 2 *(2^m - 2)- [2^(m-1) - 2] -[2^(m-1) - 2]    cur = pre + 2^melse    cur = 3 * (2^m - 2)从1~m循环上述过程,并更新prepre = curreturn pre

有了上述关系式,写出代码如下:

/** * Author:   Mengjun Li * Date:     2017/10/14 下午9:06 * Description:只含4or7的数字称为幸运数,给定一个数n,求出不超过n的幸运数的个数 *//** * @author Mengjun Li * @create 2017/10/14 * @since 1.0.0 */public class Main2 {    public static void main(String[] args) {        int x = 4;        System.out.println("不超过" + x + "的幸运数的个数: " + cal(x));        x = 77;        System.out.println("不超过" + x + "的幸运数的个数: " + cal(x));        x = 100;        System.out.println("不超过" + x + "的幸运数的个数: " + cal(x));        x = 444;        System.out.println("不超过" + x + "的幸运数的个数: " + cal(x));        x = 777;        System.out.println("不超过" + x + "的幸运数的个数: " + cal(x));        x = 888;        System.out.println("不超过" + x + "的幸运数的个数: " + cal(x));        x = 21857711;        System.out.println("不超过" + x + "的幸运数的个数: " + cal(x));    }    public static int cal(int num) {        //为了便于对num的每一个位进行操作,将其转化为String对象        String str = String.valueOf(num);        int len = str.length();        int pre, cur = 0;        if (str.charAt(len - 1) < '4')            pre = 0;        else if (str.charAt(len - 1) < '7')            pre = 1;        else            pre = 2;        int index = len - 2, tmp = 0;        final int div = (int) (Math.pow(10,9)+7);        while (index >= 0) {            tmp = str.charAt(index) - '0';            if (tmp < 4)                cur = (1 << len - index) - 2;            else if (tmp == 4)                cur = pre + (1 << len - index - 1);            else if (tmp < 7)                cur = (1 << len - index + 1) - 4;            else if (tmp == 7)                cur = pre + (1 << len - index);            else                cur = (1 << len - index + 1) - 2;            index--;            pre = cur % div;        }        return pre;    }}

输出如下:

不超过4的幸运数的个数: 1不超过77的幸运数的个数: 6不超过100的幸运数的个数: 6不超过444的幸运数的个数: 7不超过777的幸运数的个数: 14不超过1000的幸运数的个数: 14不超过21857711的幸运数的个数: 254
原创粉丝点击