計(jì)算1至n中數(shù)字X出現(xiàn)的次數(shù)

參考文獻(xiàn):http://www.cnblogs.com/cyjb/p/digitOccurrenceInRegion.html

一、1的數(shù)目

編程之美上給出的規(guī)律:

1. 如果第i位(自右至左,從1開(kāi)始標(biāo)號(hào))上的數(shù)字為0,則第i位可能出現(xiàn)1的次數(shù)由更高位決定(若沒(méi)有高位,視高位為0),等于更高位數(shù)字X當(dāng)前位數(shù)的權(quán)重10i-1。

2. 如果第i位上的數(shù)字為1,則第i位上可能出現(xiàn)1的次數(shù)不僅受更高位影響,還受低位影響(若沒(méi)有低位,視低位為0),等于更高位數(shù)字X當(dāng)前位數(shù)的權(quán)重10i-1+(低位數(shù)字+1)。

3. 如果第i位上的數(shù)字大于1,則第i位上可能出現(xiàn)1的次數(shù)僅由更高位決定(若沒(méi)有高位,視高位為0),等于(更高位數(shù)字+1)X當(dāng)前位數(shù)的權(quán)重10i-1。

二、X的數(shù)目

這里的 X∈[1,9],因?yàn)?X=0 不符合下列規(guī)律,需要單獨(dú)計(jì)算。

首先要知道以下的規(guī)律:

  • 從 1 至 10,在它們的個(gè)位數(shù)中,任意的 X 都出現(xiàn)了 1 次。
  • 從 1 至 100,在它們的十位數(shù)中,任意的 X 都出現(xiàn)了 10 次。
  • 從 1 至 1000,在它們的百位數(shù)中,任意的 X 都出現(xiàn)了 100 次。

依此類(lèi)推,從 1 至 10i,在它們的左數(shù)第二位(右數(shù)第 i 位)中,任意的 X 都出現(xiàn)了 10i?1次。

這個(gè)規(guī)律很容易驗(yàn)證,這里不再多做說(shuō)明。

接下來(lái)以 n=2593,X=5 為例來(lái)解釋如何得到數(shù)學(xué)公式。從 1 至 2593 中,數(shù)字 5 總計(jì)出現(xiàn)了 813 次,其中有 259 次出現(xiàn)在個(gè)位,260 次出現(xiàn)在十位,294 次出現(xiàn)在百位,0 次出現(xiàn)在千位。

現(xiàn)在依次分析這些數(shù)據(jù),首先是個(gè)位。從 1 至 2590 中,包含了 259 個(gè) 10,因此任意的 X 都出現(xiàn)了 259 次。最后剩余的三個(gè)數(shù) 2591, 2592 和 2593,因?yàn)樗鼈冏畲蟮膫€(gè)位數(shù)字 3 < X,因此不會(huì)包含任何 5。(也可以這么看,3<X,則個(gè)位上可能出現(xiàn)的X的次數(shù)僅由更高位決定,等于更高位數(shù)字(259)X101-1=259)。

然后是十位。從 1 至 2500 中,包含了 25 個(gè) 100,因此任意的 X 都出現(xiàn)了 25×10=250 次。剩下的數(shù)字是從 2501 至 2593,它們最大的十位數(shù)字 9 > X,因此會(huì)包含全部 10 個(gè) 5。最后總計(jì) 250 + 10 = 260。(也可以這么看,9>X,則十位上可能出現(xiàn)的X的次數(shù)僅由更高位決定,等于更高位數(shù)字(25+1)X102-1=260)。

接下來(lái)是百位。從 1 至 2000 中,包含了 2 個(gè) 1000,因此任意的 X 都出現(xiàn)了 2×100=200 次。剩下的數(shù)字是從 2001 至 2593,它們最大的百位數(shù)字 5 == X,這時(shí)情況就略微復(fù)雜,它們的百位肯定是包含 5 的,但不會(huì)包含全部 100 個(gè)。如果把百位是 5 的數(shù)字列出來(lái),是從 2500 至 2593,數(shù)字的個(gè)數(shù)與百位和十位數(shù)字相關(guān),是 93+1 = 94。最后總計(jì) 200 + 94 = 294。(也可以這么看,5==X,則百位上可能出現(xiàn)X的次數(shù)不僅受更高位影響,還受低位影響,等于更高位數(shù)字(2)X103-1+(93+1)=294)。

最后是千位?,F(xiàn)在已經(jīng)沒(méi)有更高位,因此直接看最大的千位數(shù)字 2 < X,所以不會(huì)包含任何 5。(也可以這么看,2<X,則千位上可能出現(xiàn)的X的次數(shù)僅由更高位決定,等于更高位數(shù)字(0)X104-1=0)。

到此為止,已經(jīng)計(jì)算出全部數(shù)字 5 的出現(xiàn)次數(shù)。

總結(jié)一下以上的算法,可以看到,當(dāng)計(jì)算右數(shù)第 i 位包含的 X 的個(gè)數(shù)時(shí):

  1. 取第 i 位左邊(高位)的數(shù)字,乘以 10i?1,得到基礎(chǔ)值 a。
  2. 取第 i 位數(shù)字,計(jì)算修正值
    1. 如果大于 X,則結(jié)果為 a+10i?1。
    2. 如果小于 X,則結(jié)果為 a。
    3. 如果等 X,則取第 i 位右邊(低位)數(shù)字,設(shè)為 b,最后結(jié)果為 a+b+1。

相應(yīng)的代碼非常簡(jiǎn)單,效率也非常高,時(shí)間復(fù)雜度只有 O(log10n)。

三、上代碼

    /**
     * @param n
     * @param x [1,9]
     * @return
     */
    public int NumberOfXBetween1AndN_Solution(int n,int x) {
        if(n<0||x<1||x>9)
            return 0;
        int high,low,curr,tmp,i = 1;
        high = n;
        int total = 0;
        while(high!=0){
            high = n/(int)Math.pow(10, i);// 獲取第i位的高位
            tmp = n%(int)Math.pow(10, i);
            curr = tmp/(int)Math.pow(10, i-1);// 獲取第i位
            low = tmp%(int)Math.pow(10, i-1);// 獲取第i位的低位
            if(curr==x){
                total+= high*(int)Math.pow(10, i-1)+low+1;
            }else if(curr<x){
                total+=high*(int)Math.pow(10, i-1);
            }else{
                total+=(high+1)*(int)Math.pow(10, i-1);
            }
            i++;
        }
        return total;        
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容