编码练习: 函数求值
题目:函数求值
附加描述
假设存在一个正整数M,用Func(M)表示所有<=M的自然数中所有位数为1和2的个数之和。
例如:当M为12时,得到的所有自然数为1,2,3,4,5,6,7,8,9,10,11,12;所有位数为1和2的个数之和为7(1,2,10,11,12),因此 Func(12)=7。
输入M,求Func(M)的值,若Func(M)得到的值超过20123,则算出Func(M)mod20123的值
样例输入
9
10
11
12
13
样例输出
2
3
5
7
8
这题和《剑指offer》的面试题#43类似,不过原题是求1~n整数中1出现的次数。
解法1
暴力法,直接遍历从1~n的整数,判断每个整数的每一位出现1和2的总数,进行累加。
取模(%)判断最低位是否为1或2,将该整数/10,循环判断最低位直到该整数变为0。
/*时间复杂度为O(N*LogN)*/
int Func(int M){
int count = 0; /*计数*/
int temp;
if(M <= 0){
return 0;
}
for(int i = 1; i <= M; i++){
temp = i;
while(temp > 0){
if((temp % 10) == 1 || (temp % 10) == 2){
count++;
}
temp /= 10;
}
}
return count;
}
解法2
找数字的规律,在《剑指offer》面试题#43的解法上进行小修改。
思路是参考《剑指offer》的。
以31345为例:
为了方便递归实现,将一个数拆分成除最高位外的部分和剩余部分(31345拆为1-1345和1346-31345两部分,这样去掉最高位的3就剩下了1345)。
对于1346-31345,目前只考虑最高位(万位)的情况,1只会出现在1000019999区间,出现10000次,2只会出现在2000029999区间,出现10000次。
列几个数看看:
对于12345这样的数,最高位是1,那么只考虑最高位的情况下,1出现的次数是2345+1=2346次,2出现的次数是0次;
对于22345这样的数,最高位是2,那么只考虑最高位的情况下,1出现的次数是10000次,2出现的次数是2345+1=2346次;
对于32345这样的数,最高位是3,那么只考虑最高位的情况下,1出现的次数是10000次,2出现的次数是10000次;
对于42345这样的数,最高位是4,那么只考虑最高位的情况下,1出现的次数是10000次,2出现的次数是10000次;
我们需要对整数的最高位进行判断,是等于1,等于2,还是大于2。然后递归依次判断剩余位数即可。
/*对数字找规律*/
int NumberOf1And2Between1AndN(int n){
if(n <= 0)
return 0;
/*将数字转为字符串进行处理*/
char str[40];
sprintf(str, "%d", n);
return NumberOf1And2(str);
}
int NumberOf1And2(const char* str){
/*字符指针为空,或字符非法,或到了字符串末尾,则直接返回0*/
if(!str || *str < '0' || *str > '9' || str == '\0'){
return 0;
}
int first = *str - '0';
unsigned int length = strlen(str);
/*以下判断主要作为递归的终止条件*/
if(length == 1&& first ==0)
return 0;
else if(length == 1 && first == 1)
return 1;
else if(length == 1 && first >= 2)
return 2;
int numFistDigit = 0;
if(first > 2){
/*1出现PowerBase10(length - 1)次,2出现PowerBase10(length - 1)次,比如31345,最高位的1出现10^4次。*/
numFistDigit = 2 * PowerBase10(length - 1);
}else if(first == 1){
numFistDigit = atoi(str + 1) + 1;
}else if(first == 2){
numFistDigit = PowerBase10(length - 1) + atoi(str + 1) + 1;
}
/*以31345为例,固定最高位,剩下4位数中,固定其中的1位数来选1或者选2,剩余3位中,每一位都有10种可能*/
int numOtherDigits = 2 * first * (length - 1) * PowerBase10(length - 2);
/*递归处理除最高位外其它位*/
int numRecursive = NumberOf1And2(str+1);
return numFistDigit + numOtherDigits + numRecursive;
}
int PowerBase10(unsigned int n){
/*计算10的n次方---简洁版本*/
int result = 1;
for(unsigned int i = 0; i < n; ++i)
result *= 10;
return result;
}