面试题43: 1-n整数中1出现的次数
题目:输入一个整数n,求1-n这n个整数的十进制表示中1出现的次数。例如,输入12,1-12这些整数中包含1的数字有1、10、11和12,1一共出现了5次。
解题思路:
假设数为21345。
将21345分为1 ~ 1345、1346 ~ 21345三部分。
对于1346 ~ 21345,
分析最高位为1,即1出现在万位的次数。如果最高为大于1,则次数为10^4次,如果最高位为1,则次数为(1345 + 1)次。
分析除最高位外的其他4位,可以把1346 ~ 21345再拆分位1346 ~ 11345和11346 ~ 21345。每一段剩下的四位数字中,选择其中一位是1,其他生于三位可以在0 ~ 9这10个数字中任意选择,根据排列组合,总出现次数为2×4×10^3。
对于1-1345,
递归。
int PowerBase10(unsigned int n) {
int result = 1;
for (unsigned int i = 0; i < n; ++i) {
result *= 10;
}
return result;
}
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"
// numFirstDigit是数字10000~19999的第一位中的数字
int numFirstDigit = 0;
if (first > 1) {
numFirstDigit = PowerBase10(length - 1);
}
else {
numFirstDigit = atoi(strN + 1) + 1;
}
// numOtherDigits是1346~21345除第一位之外的数位中的数目
int numOtherDigits = first * (length - 1) * PowerBase10(length-2);
// numRecursive是1~1345中的数目
int numRecursive = NumberOf1(strN+1);
return numFirstDigit + numOtherDigits + numRecursive;
}
int NumberOf1Between1AndN(int n) {
if (n <= 0) {
return 0;
}
char strN[50];
sprintf_s(strN, "%d", n);
return NumberOf1(strN);
}