日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

编程之美计算0到N中包含数字1的个数

發布時間:2025/7/25 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 编程之美计算0到N中包含数字1的个数 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉自:http://blog.csdn.net/hongjuntu123/article/details/8743266

有這樣一個函數f(n),對于任意正整數n,它表示從 0 到 n 之間出現“1”的個數,比如 f(1) = 1, f(13) = 6,請列出從 1 到 1234567890 中所有的 f(n) = n 的n, 要求準確快速.

?

相信很多人都能立刻得出以下的解法:

??for(n:N)

??{

??????????判斷n包含1的個數;

??????????累加計數器;

??}

這是最直接的解法,但遺憾的是,時間復雜程度為O(N*logN)。因為還需要循環判斷當前的n的各位數,該判斷的時間復雜程度為O(logN)。

接下來就應該思考效率更高的解法了。說實話,這道題讓我想起另外一道簡單的算法題:

N為正整數,計算從1到N的整數和。

很多人都采用了循環求解。然后利用初等數學知識就知道S=N*(N+1)/2,所以用O(1)的時間就可以處理。

再回到本道題目,同理應該去尋找到結果R與N之間的映射關系。

分析如下:

假設N表示為a[n]a[n-1]...a[1],其中a[i](1<=i<=n)表示N的各位數上的數字。

c[i]表示從整數1到整數a[i]...a[1]中包含數字1的個數。

x[i]表示從整數1到10^i - 1中包含數字1的個數,例如,x[1]表示從1到9的個數,結果為1;x[2]表示從1到99的個數,結果為20;

當a[1]=0時,c[1] = 0;

當a[1]=1時,c[1] = 1;

當a[1]>1時,c[1] = 1;

?

當a[2]=1時,c[2] = a[1] +1+ c[1] + x[1];

當a[2]>1時,c[2] = a[2]*x[1]+c[1]+10;

?

當a[3]=1時,c[3] = a[2]*a[1] +1+ c[2] + x[2];

當a[3]>1時,c[3] = a[3]*x[2]+c[2]+10^2;

......

?

以此類推

當a[i]=1時,c[i] = a[i-1]*...*a[1] +1+ c[i-1]+x[i-1];

當a[i]>1時,c[i] = a[i]x[i-1]+c[i-1]+10^(i-1);

?

?

實現的代碼如下:

?

Java代碼?
  • public?static?int?search(int?_n)??????
  • {??????
  • ????int?N?=?_n/10;??????
  • ????int?a1?=?_n%10,a2;??????
  • ????int?x?=?1; ??
  • ????int?ten?=?10; ??
  • ????int?c?=?a1?==?0?0:1; ??
  • ????while(N?>?0)??????
  • ????{??????
  • ????????a2?=?N%10; ??
  • ????????if(a2?==?0); ??
  • ????????else?if(a2?==?1)c?=?a1?+?1?+?x?+?c;??????
  • ????????else?c?=?a2*x?+?c?+?ten;??????
  • ????????a1?=?10*a1?+?a2;????????
  • ????????N?/=10;??????
  • ????????x?=?10*x?+?ten; ??
  • ????????ten?*=?10;????
  • ????}??????
  • ????return?c;??????
  • }??
  • ?

    ?

    而以上解法的時間復雜程度只有O(logN)

    ?

    ?

    ?

    ?

    ?

    ?

    /

    編程之美之1的數目

    2010/09/07?異淚?技術?309views |?Go to comment

    1 的數目

    給定一個十進制正整數 N,寫下從 1 開始,到 N 的所有整數,
    然后數一下其中出現的所有“1”的個數。
    例如:
    N= 2,寫下 1,2。這樣只出現了 1 個“1”。
    N= 12,我們會寫下 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12。這樣,1的個數是 5。
    問題是:
    寫一個函數f(N) 返回1到N之間出現的“1”的個數,比如f(12)=5。

    這個問題看上去并不是一個困難的問題,因為不需要太多的思考,大家都能找到一個最簡單的方法來計算 f(N),那就
    是從1開始遍歷到N,將其中每一個數中含有“1”的個數加起來,
    自然就得到了從1到N所有“1”的個數的和.C語言實現如下:

    #include<stdio.h>
    int?Count1(int?n)
    {
    ????int?iNum=0;
    ????while(n!=0)
    ????{
    ????????iNum+=(n%10==1)?1:0;
    ????????n/=10;
    ??????????????
    ????}
    ????return?iNum;
    }

    int?Count2(int?n)
    {
    ????int?iCount=0;
    ????for(int?i=0;i<=n;i++)
    ????{
    ????????iCount+=Count1(i);
    ????}?
    ????return?iCount;?
    }

    int?main()
    {
    ?????int?x;
    ?????scanf("%d",&x);
    ?????printf("%d",Count2(x));
    ?????return?0;
    }

    但是這個算法的致命問題是效率,它的時間復雜度是O(N)×計算一個整數數字里面“1”的個數的復雜度 = O(N *log2 N),如果給定的 N 比較大,則需要很長的運算時間才能得到計算結果。我試著輸入100000000,一共用了大概12秒,貌似有點長,不夠比作者說的40S快多了,作者的電腦有點舊…….- .-

    解法二

    <編程之美>先從一些簡單的情況開始觀察:

    如果N是一位數,可以確定f(N)=1

    如過是二位數,如果 N=13,那么從 1 到 13 的所有數字:1、2、3、4、5、6、
    7、8、9、10、11、12、13,個位和十位的數字上都可能有 1,我們可以將它們分開來考慮,個位出現 1 的次數有兩次:1 和 11,十位出現 1 的次數有 4 次:10、11、12 和 13,所以 f(N)=2+4=6。要注意的是 11 這個數字在十位和個位都出現了 1, 但是 11 恰好在個位為 1 和十位為 1 中被計算了兩次,所以不用特殊處理,是對的。再考慮 N=23 的情況,它和 N=13 有點不同,十位出現 1 的次數為 10 次,從 10 到 19,個位出現 1 的次數為 1、11 和 21,所以f(N)=3+10=13。通過對兩位數進行分析,我們發現,個位數出現 1 的次數不僅和個位數字有關,還和十位數有關:如果 N 的個位數大于等于 1,則個位出現 1 的次數為十位數的數字加 1;如果N 的個位數為 0,則個位出現 1 的次數等于十位數的數字。而十位數上出現 1 的次數不僅和十位數有關,還和個位數有關:如果十位數字等于 1,則十位數上出現 1 的次數為個位數的數字加 1;如
    果十位數大于 1,則十位數上出現 1 的次數為 10。
    f(13) = 個位出現1的個數 + 十位出現1的個數 = 2 + 4 = 6;
    f(23) = 個位出現1的個數 + 十位出現1的個數 = 3 + 10 = 13;
    f(33) = 個位出現1的個數 + 十位出現1的個數 = 4 + 10 = 14;

    f(93) = 個位出現1的個數 + 十位出現1的個數 = 10 + 10 =
    20;

    接著分析 3 位數,

    如果 N = 123:

    個位出現 1 的個數為 13:1, 11, 21, …, 91, 101, 111, 121
    ?十位出現 1 的個數為 20:10~19, 110~119
    ?百位出現 1 的個數為 24:100~123

    ?f(23)= 個位出現 1 的個數 + 十位出現 1 的個數 + 百位出現 1 的次數 = 13 + 20 + 24 = 57;同理我們可以再分析 4 位數、 位數。???根據上面的一些嘗試,下面我們推導出一般情況下,從 N 得
    到 f(N)的計算方法:?假設 N=abcde,這里 a、b、c、d、e 分別是十進制數 N 的各個數位上的數字。如果要計算百位上出現 1 的次數,它將會受到三個因素的影響:百位上的數字,百位以下(低位)的數字,百
    位(更高位)以上的數字。如果百位上的數字為 0,則可以知道,百位上可能出現 1 的次
    數由更高位決定,比如 12 013,則可以知道百位出現 1 的情況可能
    是 100~199,1 100~1 199,2 100~2 199,…,11 100~11 199,
    一共有 1 200 個。也就是由更高位數字(12)決定,并且等于更高
    位數字(12)×當前位數(100)。

    如果百位上的數字為 1,則可以知道,百位上可能出現 1 的次數不僅受更高位影響,還受低位影響,也就是由更高位和低位共同決定。例如對于 12 113,受更高位影響,百位出現 1 的情況是 100~199,1 100~1 199,2 100~2 199,…,11 100~11 199,一共 1 200個,和上面第一種情況一樣,等于更高位數字(12)×當前位數(100)。但是它還受低位影響,百位出現 1 的情況是 12 100~12 113,一共114 個,等于低位數字(123)+1。?如果百位上數字大于 1(即為 2~9),則百位上可能出現 1的次數也僅由更高位決定,比如 12 213,則百位出現 1 的可能性為:100~199,1 100~1 199,2 100~2 199,…,11 100~11 199,12 100~12 199,一共有 1 300 個,并且等于更高位數字+1(12+1)
    ×當前位數(100)。通過上面的歸納和總結,我們可以寫出如下的更高效算法來
    計算 f(N):

    #include<stdio.h>
    int?Sumls(int?n)
    {
    ????int?iCount=0,iFactor=1,iLowerNum=0,iCurrNum=0,iHigherNum=0;
    ????while(n/iFactor!=0)
    ????{
    ????????iLowerNum=n-(n/iFactor)*iFactor;
    ????????iCurrNum=(n/iFactor)%10;
    ????????iHigherNum=n/(iFactor*10);
    ???????
    ????????switch(iCurrNum)
    ????????{
    ????????????case?0:
    ????????????????iCount+=iHigherNum*iFactor;
    ????????????????break;
    ????????????case?1:
    ????????????????iCount+=iHigherNum*iFactor+iLowerNum+1;
    ????????????????break;
    ????????????default:
    ????????????????iCount+=(iHigherNum+1)*iFactor;
    ????????????????break;
    ???????????????????????
    ????????}
    ????????iFactor*=10;
    ???????
    ????}
    ????return?iCount;?
    }

    int?main()
    {
    ????int?x;
    ????scanf("%d",&x);???
    ????printf("%d",Sumls(x));
    ????return?0;
    }

    我試著輸入100000000瞬間就顯示出結果了,編程之美說效率至少提高了40000倍…

    轉載于:https://www.cnblogs.com/vipwtl/p/5366877.html

    總結

    以上是生活随笔為你收集整理的编程之美计算0到N中包含数字1的个数的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。