题目来自剑指Offer
题目:
思路一:暴力法
方法:对1到n中的每一个数,分别判断其中1的个数。
复杂度:O(n*logn)
代码:
#include <iostream> #include <assert.h> using namespace std; int OneNum(int n) { assert(n >= 0); int nSum = 0; int nCurNum = 1; for (int i = 1;i <= n;i++) { nCurNum = i; while (nCurNum) { if (nCurNum % 10 == 1) { nSum++; } nCurNum /= 10; } } return nSum; } int main() { cout<<OneNum(1)<<endl; //1 cout<<OneNum(11)<<endl; //4 cout<<OneNum(111)<<endl;//36 cout<<OneNum(123)<<endl;//57 cout<<OneNum(93)<<endl; //20 system("pause"); return 1; }
思路二:找规律,可以直接根据数n中每一个数字来判断包含1的个数
复杂度为O(len),len表示数n包含的数字个数。
方法:
假设数字为abcde,对于abcde中的每一个数字,可以根据该数字与1的关系,求在该数字对应位置上1出现的次数。
具体来说:
假设我们要求百位出现1的次数,此时我们可以根据c与1的关系,求出百位1出现的次数。
(1)如果c = 0,则1出现的次数等于ab * 100,即 c前面的数 * c对应的基数
在该情况下,百位出现1的次数只与c前面的数有关。
(2)如果c = 1,则1出现的次数等于(ab * 100) + (de + 1),即(c前面的数 * c对应的基数) +( c后面的数 + 1)
在该情况下,百位出现1的次数与c前面和c后面的数有关。
(3)如果c = 2,则1出现的次数等于(ab + 1)*100,即(c前面的数 +1)* c对应的基数
在该情况下,百位出现1的次数只与c前面的数有关。
举例:
对于12013,在百位处出现1的次数= 12 * 100 = 1200次
其分别是,00100 -00199,01100 -01199,02100 - 02199,...,11100 - 11199。
(1)由于因为百位 = 0,则以12为开头的数不会含有1。
(2)百位前面的数值能有00 - 11,即出现12次。由于百位后的数字有两位,因此其基数为100。
即,以00 - 11为开头的数,后面都可以由00 变化到99,即包含了所有1的情况。
--------------------------------------
对于12113,在百位处出现1的次数= (12 * 100 ) + (13+1)= 1214次
(1)包含足够1的情况:00100 - 00199,01100 - 01199,02100 - 02199,...,11100 - 11199
(2)包含部分1的情况:12100 - 12113
即,由于百位 = 1,则以00 - 12为开头的数在百位都含有1。
(1)当百位前面的数字为00-11时,此情况包含了所有1的情况。(00-99)
(2)当百位前面为数字为12时,此情况仅仅包含了部分1的情况(00-13)
---------------------------------------
对于12213,在百位处出现1的次数= (12+1) * 100 = 1300次
其分别是,00100 - 00199,01100 - 01199,02100 - 02199,...,11100 - 11199,12100 - 12199。
此时,百位前面的数无论怎么变化,后面都可以由00 变化到99,即包含了所有1的情况。
代码:
#include <iostream> #include <assert.h> using namespace std; int OneNum(int n) { assert(n >= 0); int nCurBit = n % 10; //待处理的每一位 int nForward = n / 10; //nCurBit前面的数 int nBackward = 0; //nCurBit后面的数 int nBase = 1; int nSum = 0; while (n / nBase) { if (nCurBit == 0) { nSum += nForward * nBase; } else if (nCurBit == 1) { nSum += nForward * nBase; nSum = nSum + nBackward + 1; } else { nSum += (nForward + 1) * nBase; } nCurBit = nForward % 10; nBase *= 10; nForward = n / (nBase * 10); nBackward = n % nBase; } return nSum; } int main() { cout<<OneNum(1)<<endl;//1 cout<<OneNum(11)<<endl;//4 cout<<OneNum(111)<<endl;//36 cout<<OneNum(123)<<endl;//57 cout<<OneNum(93)<<endl;//20 cout<<OneNum(0)<<endl;//0 cout<<OneNum(9999)<<endl;//0 system("pause"); return 1; }