從1到N整數中1出現的次數

2021-10-07 22:20:44 字數 3533 閱讀 7650

給定乙個整數 n,計算所有小於等於 n 的非負整數中數字 1 出現的個數。 

示例:輸入: 13

輸出: 6 

解釋: 數字 1 出現在以下數字中: 1, 10, 11, 12, 13 。

能想到最直觀的方法(說實話 ,我沒想到 , 第一眼我認為這是乙個數學題, 根本沒有想到用計算機的思路解決問題), 也就是累加1到n中每個整數1出現的次數。我們可以每次通過對10求餘數判斷整數的個位數字是不是1。如果這個數字大於10,除以10之後再判斷個位數字是不是1。 所以第乙個方法就出來了.  

這個演算法還是很有必要的, 後續的演算法需要依靠這個來驗證是否正確 , 有了這個演算法才能孵化出更好的演算法.

- (int)countnumfun:(int)n

nslog(@"第一種方法:1-%d之間出現了%d個",n,count);

return count;

}- (int)__numof1count:(int)num

num /=10;

}if (count>0)

return count;

}

每乙個數字都需要處理,需要n次; 

在對任意乙個數字處理的時候 ,由於每次都是/10,  需要logn次 ;

總體的時間複雜度是o(n*logn). 

現在有了乙個暫時能用的演算法了, 現在把這個當成乙個數學題 , 通過數學方法看看能不能求解. 

先來乙個例子, 比如n=215.我們按照個位,十位,百位來計算每個位值上1出現的次數.

先從個位開始, 個位要想出現1,只有這種001,011,021,031,.......101,111,121,.....201,211 , 從001到211總共是22個, 其中21個是必定出現的, 最後乙個211,需要看情況, 如果n=210,那麼211就不會有了.

在看十位, 010,011,012,013,...,018,019,   110,111,112,113,....,118,119,   210,211,212,... 215, 總共是26個, 前面20個(2*10, 010到019, 110到119, )也是必定出現的, 後面的最後幾個需要看情況

在看百位,100,101,102,103...198,199,    總共出現了100個.

通過手動計算,發現總共是 22+26+100=148個.

在來乙個例子, n=555,

個位上 , 總共出現了56次,  這個56次怎麼出來的呢, 0-9出現了55次,尾巴上0-5出現了1次,加起來是56次.

十位上,  總共出現了6次010-019, 110-119, 210-219,....510-519,     010到510出現了5次完整的,  每次有10個1 , 尾巴也是乙個完整的, 因為十位的5比1大,所以是60個.

百位上, 出現了100次, 100-199, 尾巴的話是乙個完整的, 因為百位的5比1大.

通過數學上的分析**發現, 這個確實不好求, 1出現的個數與"所在的位數""這個位上的值是否大於1"有關,

先這個看位數是否大於1的影響, 這個影響到尾巴值 , 如果》1, 那就可以拿到這一位的所有值, 比如555,十位的5>1, 可以拿到乙個完整十位上10個;  而501中,十位為0, 則十位上是1個都拿不到 ; n=515, 十位為1, 可以拿到部分,  要看  餘數+1就是515十位能拿到的1個數.

在看位數的影響 , 如果是在百位 , 可以拿100個, 在10位最多是10個, 各位的話,最多1個. 位數影響了乙個相乘係數.

總結來看 , 每一位似乎是乙個  ax + b  ,a是總共出現了多少次;x是係數,和位數有關,個位只有1,十位是10,百位是100.... ; b這個位數上的值與1的關係,也就是尾巴值

以543為例 , 個位出現543/10=54次完整的,x是1, 尾巴上是3 ,  3大於1 , 尾巴是1, 個位上總計55次

十位上, 543/100=5個完整的, x是10, 尾巴是4, 4大於1, 可以拿完整的10個, 十位上總計是60次

百位上, 543/1000=0個完整, x是100, 尾巴是5 , 5大於1, 可以拿完整的100個, 百位上是100次

信心滿滿, 開始操作.

nslog(@"%d位上出現了%d個", b,each);

count += each;

// 保證tempn%10是某位上的值

tempn /= 10;

// 求下一位

b *= 10;

}nslog(@"第二種方法:1-%d之間出現了%d個",n,count);

看起來效果不錯, 至少555這個值是正確的, 測試用例來一波,  1~10000之間的數字逐個驗證 ,  在隨機1000個大數驗證

時間上 第乙個演算法o(n*logn)明顯慢了下來,  需要1-3秒了;  第二個演算法o(logn)還是比較快的, 都是毫秒級的.

最後leetcode跑一下. 第乙個演算法超時, 第二個演算法還不錯.

別看第二個演算法 最後很簡潔,  在實際寫的過程中用了一晚上的時間才完善 , 總結出ax+b, 找出這個關係之後才開始豁然開朗,一馬平川起來.

整數中1出現的次數(從1到n整數中1出現的次數)

求出1 13的整數中1出現的次數,並算出100 1300的整數中1出現的次數?為此他特別數了一下1 13中包含1的數字有1 10 11 12 13因此共出現6次,但是對於後面問題他就沒轍了。acmer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區間中1出現的次數。include u...

整數中1出現的次數(從1到n整數中1出現的次數)

時間限制 1秒 空間限制 32768k 題目描述 include using namespace std class solution 求之前的length 1位中含乙個數 int base1 0 int base2 1 for int i 0 i1 i cout cout cout 求從base2...

整數中1出現的次數(從1到n整數中1出現的次數)

求出1 13的整數中1出現的次數,並算出100 1300的整數中1出現的次數?為此他特別數了一下1 13中包含1的數字有1 10 11 12 13因此共出現6次,但是對於後面問題他就沒轍了。acmer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區間中1出現的次數。演算法一 暴力累加...