题目是这样的:给定一个正整数N,从1到N一共出现过多少个1?
如N=12,则f(12)=5,因为1,2,3,4,5,6,7,8,9,10,11,12共出现5次“1”。
书上的思路很巧妙,考虑到一个数字的每一位中1出现的次数,如果该位为0,则该位出现1的数目只与其前面的数字有关,如果为1,则与前面后面数字都有关,如大于1,仍只与前面数字有关。Java代码如下:
public void Book(){
int n = num;
int iCount = 0;
int iFactor = 1;
int iLowerNum = 0;
int iCurrentNum = 0;
int iHigherNum = 0;
while(n/iFactor != 0){
iLowerNum = n – (n / iFactor) * iFactor;
iCurrentNum = n / iFactor % 10;
iHigherNum = n / (iFactor * 10);
switch(iCurrentNum){
case 0:
iCount += iHigherNum * iFactor;
break;
case 1:
iCount += iHigherNum * iFactor + iLowerNum + 1;
break;
default:
iCount += (iHigherNum + 1) * iFactor;
break;
}
iFactor *= 10;
}
System.out.println(“The biaozhun anwser is ” + iCount);
}
自己的算法:
分别考虑不同位数的数字中1出现的个数。这种方法没有书上给出的简单,但是结果是正确的。
具体是这样的:
书中有公式:f(10^n – 1) = n * 10^(n – 1);即n位数中最多有1的个数是n*10^(n – 1),如3位数最大为999,从1至999共有 3 * 10 ^2 = 300个。
先给出一个N位数x,可以先利用上面公式求出(N – 1)位及以下所有数字中包含1的个数,剩下只需求解所有小于等于x的N位数中包含1的个数。
如x = 23435,先利用公式求出所有4位数中(1至9999)包含1的个数 ,为 4000个。然后求解10000到23435中1的个数。在求解N位数中包含1的个数时
需要注意某位前面的数字是有限制的,因为它是从最小的N位数10000(N个0)开始的。
具体代码如下:
public void MyCal2(){
int length = 0, tmp = num;
//求出该数字的位数
while(tmp > 0){
length++;
tmp /= 10;
}
System.out.println(“length = ” + length);
//求出所有len – 1到1位的所有包含1的结果
int sum = cal(length – 1);
int pow = (int)Math.pow(10, length – 1);
System.out.println(“The init result is ” + sum + “, the length = ” +
“, the pow = ” + pow);
int current = num / pow;
int pre = 0;
int pos = num – current * pow;
int left = (current == 1) ? (pos + 1): pow;
for(int idx = length – 1; idx >= 1; idx–){
//pow /= 10;
pre = num / pow;
current = (num – pre * pow )/(pow / 10);
pos = num % pow – current * (pow / 10);
System.out.println(“In the calculation2, the pre is ” +
pre + ” current = ” + current + “, pos = ” + pos
+ “, pow = ” + pow );
pre -= (int)Math.pow(10, length – idx -1);
pre += 1;
System.out.println(“After translation, the pre is ” +
pre );
if(current > 1){
left += pre * (int)Math.pow(10, idx – 1);
} else if(current == 1){
left += (pre – 1) * (int)Math.pow(10, idx – 1) + pos + 1;
}else if(current == 0){
left += (pre – 1) * (int)Math.pow(10, idx – 1);
}
pow /= 10;
}
System.out.println(“In the calculation2, the result is ” + (sum + left));
}