給定乙個整數 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,通過數學上的分析**發現, 這個確實不好求, 1出現的個數與"所在的位數""這個位上的值是否大於1"有關,個位上 , 總共出現了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, 那就可以拿到這一位的所有值, 比如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出現的次數。演算法一 暴力累加...