求出不超過n的幸運數

題目描述:

對於某一個數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           47
2       2+4=6       4744477477
3       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^m
else
    cur = 3 * (2^m - 2)
從1~m循環上述過程,並更新pre
pre = cur

return 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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章