题目
2.4 1的数目
给定一个十进制正整数N,写下从1开始,到N所有整数,然后数一下其中出现的所有“1”的个数。
例如:N = 2 则在1,2中只出现了1个“1”
N = 12 则在1~12中出现了5个“1”
实现一个函数:返回1到N之间出现的“1”的个数,比如f(12) = 5;
问:满足条件f(N) = N 的最大的N是多少?
分析
解析见:
《编程之美》P132
《程序员代码面试指南》P429
代码
/*
2.4 1的数目
给定一个十进制正整数N,写下从1开始,到N所有整数,然后数一下其中出现的所有“1”的个数。
例如:N = 2 则在1,2中只出现了1个“1”
N = 12 则在1~12中出现了5个“1”
实现一个函数:返回1到N之间出现的“1”的个数,比如f(12) = 5;
问:满足条件f(N) = N 的最大的N是多少?
*/
#include <iostream>
#include <cstdlib>
using namespace std;
/*方法一:复杂度O(nlogn)*/
int count1(int n)
{
int iCount = 0;
while (n != 0)
{
iCount += (n % 10 == 1) ? 1 : 0;
n /= 10;
}//while
return iCount;
}
int sum1s(int n)
{
int iCount = 0;
for (int i = 1; i <= n; ++i)
{
iCount += count1(i);
}//for
return iCount;
}
/*方法二:复杂度O(N的位数) 《编程之美》p134*/
int sum1s_2(int n)
{
int iCount = 0;
int iFactor = 1;
int 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;
}//switch
iFactor *= 10;
}//while
return iCount;
}
/*方法三:复杂度O(logN*logN) 《程序员代码面试指南》 P429*/
int lenOfN(int n)
{
int len = 0;
while (n != 0)
{
++len;
n /= 10;
}//while
return len;
}
int powerBaseOf10(int base)
{
return pow(10, base);
}
int sum1s_3(int n)
{
if (n < 1)
{
return 0;
}//if
int len = lenOfN(n);
if (1 == len)
{
return 1;
}//if
int tmp1 = powerBaseOf10(len - 1);
int first = n / tmp1;
int firstOneNum = first == 1 ? n % tmp1 + 1 : tmp1;
int otherOneNum = first * (len - 1) * (tmp1 / 10);
return firstOneNum + otherOneNum + sum1s_3(n % tmp1);
}
int main()
{
cout << sum1s(12) << endl;
cout << sum1s_2(12) << endl;
cout << sum1s_3(12) << endl;
system("pause");
return 0;
}