面试题43:从1到n整数中1出现的次数
题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。例如输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次。
解决方法:
- ◈不考虑时间效率的解法,靠它想拿到 Offer 有点难
#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
using namespace std;
int NumberOf1(unsigned int n){
int number=0;
while(n){
if(n%10==1) number++;
n/=10;
}
return number;
}
int NumberOf1Between1AndN(unsigned int n){
int number=0;
for(unsigned int i=1;i<=n;i++){
number+=NumberOf1(i);
}
return number;
}
int main() {
printf("%d\n",NumberOf1Between1AndN(100));
return 0;
}
- ◈从数字规律着手明显提高时间效率的解法,能让面试官耳目一新
#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
#include<cstring>
#include<cmath>
using namespace std;
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>1) return 1;
// 假设 strN 是 "21345"
// numFirstDigit 是数字 10000~19999 的第一位中的数目
int numFirstDigit=0;
if(first>1) numFirstDigit=(int)pow(10, length-1);
else if(first==1) numFirstDigit=atoi(strN+1)+1;
// numOtherDigits 是 1346~21345 除第一位之外的数位中的数目
int numOtherDigits=first*(length-1)*((int)(pow(10, 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(strN, "%d", n);
return NumberOf1(strN);
}
int main() {
printf("%d\n",NumberOf1Between1AndN(21345));
return 0;
}