// 面试题43:从1到n整数中1出现的次数
// 题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。例如
// 输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次。
#include <iostream>
#include <cstring>
#include <cstdlib>
// ====================方法一====================
//逐个判断,时间复杂度为O(nlogn),不好
int NumberOf1(unsigned int n);
int NumberOf1Between1AndN_Solution1(unsigned int n)
{
int number = 0;
for (unsigned int i = 1; i <= n; ++i)
number += NumberOf1(i);
return number;
}
int NumberOf1(unsigned int n)
{
int number = 0;
while (n)
{
if (n % 10 == 1)
number++;
n = n / 10;
}
return number;
}
// ====================方法二====================
int NumberOf1(const char* strN);
int PowerBase10(unsigned int n);
int NumberOf1Between1AndN_Solution2(int n)//把数字换成字符串,方便处理
{
if (n <= 0)
return 0;
char strN[50];
sprintf(strN, "%d", n);//格式化输出成字符串
return NumberOf1(strN);
}
int NumberOf1(const char* strN)
{
if (!strN || *strN < '0' || *strN > '9' || *strN == '\0')
return 0;
int first = *strN - '0';//第一位的最大值
unsigned int length = static_cast<unsigned int>(strlen(strN));//强制转换符
if (length == 1 && first == 0)//边界特殊情况
return 0;
if (length == 1 && first > 0)
return 1;
// 假设strN是"21345"
//先计算第一种情况,第一位为1的个数
// numFirstDigit是数字10000-19999的第一个位中1的数目
int numFirstDigit = 0;
if (first > 1)
numFirstDigit = PowerBase10(length - 1);
else if (first == 1)
numFirstDigit = atoi(strN + 1) + 1;//若在1xx的情况,个数不到PowerBase10(length - 1),atoi是字符串转整数
//第二种情况,非第一位为1的个数
// numOtherDigits是01346-21345除了第一位之外的数位中1的数目
int numOtherDigits = first * (length - 1) * PowerBase10(length - 2);//第一位可能性有first个,第二项表示选取除了第一位的任一位为1,剩下的有10种可能
// numRecursive是1-1345中1的数目,使用迭代处理
int numRecursive = NumberOf1(strN + 1);
return numFirstDigit + numOtherDigits + numRecursive;
}
int PowerBase10(unsigned int n)//10的n次方
{
int result = 1;
for (unsigned int i = 0; i < n; ++i)
result *= 10;
return result;
}
// ====================测试代码====================
void Test(const char* testName, int n, int expected)
{
if (testName != nullptr)
printf("%s begins: \n", testName);
if (NumberOf1Between1AndN_Solution1(n) == expected)
printf("Solution1 passed.\n");
else
printf("Solution1 failed.\n");
if (NumberOf1Between1AndN_Solution2(n) == expected)
printf("Solution2 passed.\n");
else
printf("Solution2 failed.\n");
printf("\n");
}
void Test()
{
Test("Test1", 1, 1);
Test("Test2", 5, 1);
Test("Test3", 10, 2);
Test("Test4", 55, 16);
Test("Test5", 99, 20);
Test("Test6", 10000, 4001);
Test("Test7", 21345, 18821);
Test("Test8", 0, 0);
}
int main(int argc, char* argv[])
{
Test();
system("pause");
return 0;
}