正整数中数字1的计数问题(上)
原题出自Google的一道比较老的面试题:
Consider a function which, for a given whole number n, returns the number of ones required when writing out all
numbers between 0 and n.
For example, f(13)=6. Notice that f(1)=1. What is the next largest n such that f(n)=n?
本实现没有利用可能存在的数学公式,只考虑相邻两个数得变化规律,因此运行效率并不理想。如何计算单个值f(n)的快速算法,请参考我的另一篇文章。
int prevDigitIndex = digitsCount - 2;
int leastDigitIndex = digitsCount - 1;
if(prevDigitIndex<0){ //one-digit input
System.out.format("n=%d=f(n)%n",0);
if(n>0)
System.out.format("n=%d=f(n)%n",1);
int count = 0;
if(n<=1){ //0 and 1
count = (int)n;
}else{
count = 1;
}
return count;
}
//initialized to zero
byte[] digits = new byte[digitsCount];
long totalOnesCount = 0;
int nextOnesCount = 0;
int k=0; //the least significant digit: from 0 to 9
for(long i=0;i<=n;i++){
int currOnesCount = nextOnesCount;
if(k==0){ //x0 - > x1
digits[leastDigitIndex] = 1;
nextOnesCount = currOnesCount + 1;
}else if(k==1){ //x1 - > x2
digits[leastDigitIndex] = 2;
nextOnesCount = currOnesCount - 1;
}else if(k==9){ //x9 -> ...
byte nextDigit = digits[prevDigitIndex]; //x
switch(nextDigit){
case 0: //09 -> 10
digits[prevDigitIndex] = 1;
digits[leastDigitIndex] = 0;
nextOnesCount = currOnesCount + 1;
break;
case 1: //19 -> 20
digits[prevDigitIndex] = 2;
digits[leastDigitIndex] = 0;
nextOnesCount = currOnesCount - 1;
break;
case 9: //99
int tmpIndex = prevDigitIndex;
digits[leastDigitIndex] = 0;
digits[prevDigitIndex] = 0;
while((--tmpIndex)>=0 && digits[tmpIndex]==9){
digits[tmpIndex] = 0;
}
if(tmpIndex>=0){
int d = (digits[tmpIndex]+=1);
if(d==2){ //199 -> 200
nextOnesCount = currOnesCount - 1;
}else if(d==1){ //099 -> 100
nextOnesCount = currOnesCount + 1;
}else{ //399 -> 400
nextOnesCount = currOnesCount;
}
}
break;
default: //29 ~ 89 -> 30 ~ 90
digits[prevDigitIndex] += 1;
digits[leastDigitIndex] = 0;
nextOnesCount = currOnesCount;
break;
}
}else{ //x2 ~ x8 -> x3 ~ x9
digits[leastDigitIndex] += 1;
nextOnesCount = currOnesCount;
}
k = digits[leastDigitIndex];
totalOnesCount += currOnesCount;
if(i==totalOnesCount){
System.out.format("n=%d=f(n)%n",i);
}
}
return totalOnesCount;
}
public static void main(String[] args) {
long n=1111111110;
//long n=1111111110;
//long n=1036;
long start = System.currentTimeMillis();
long ones = OnesCount.solve(n);
System.out.format("f(%d) = %d%n",n,ones);
long end = System.currentTimeMillis();
double timeElapsed = (end-start)/1000.0;
System.out.format("Time elapsed(sec): %.3f%n", timeElapsed);
}
}
测试结果(Pentium M 1.4GHz, 512M内存):
n=0=f(n)
n=1=f(n)
n=199981=f(n)
n=199982=f(n)
n=199983=f(n)
n=199984=f(n)
n=199985=f(n)
n=199986=f(n)
n=199987=f(n)
n=199988=f(n)
n=199989=f(n)
n=199990=f(n)
n=200000=f(n)
n=200001=f(n)
n=1599981=f(n)
n=1599982=f(n)
n=1599983=f(n)
n=1599984=f(n)
n=1599985=f(n)
n=1599986=f(n)
n=1599987=f(n)
n=1599988=f(n)
n=1599989=f(n)
n=1599990=f(n)
n=2600000=f(n)
n=2600001=f(n)
n=13199998=f(n)
n=35000000=f(n)
n=35000001=f(n)
n=35199981=f(n)
n=35199982=f(n)
n=35199983=f(n)
n=35199984=f(n)
n=35199985=f(n)
n=35199986=f(n)
n=35199987=f(n)
n=35199988=f(n)
n=35199989=f(n)
n=35199990=f(n)
n=35200000=f(n)
n=35200001=f(n)
n=117463825=f(n)
n=500000000=f(n)
n=500000001=f(n)
n=500199981=f(n)
n=500199982=f(n)
n=500199983=f(n)
n=500199984=f(n)
n=500199985=f(n)
n=500199986=f(n)
n=500199987=f(n)
n=500199988=f(n)
n=500199989=f(n)
n=500199990=f(n)
n=500200000=f(n)
n=500200001=f(n)
n=501599981=f(n)
n=501599982=f(n)
n=501599983=f(n)
n=501599984=f(n)
n=501599985=f(n)
n=501599986=f(n)
n=501599987=f(n)
n=501599988=f(n)
n=501599989=f(n)
n=501599990=f(n)
n=502600000=f(n)
n=502600001=f(n)
n=513199998=f(n)
n=535000000=f(n)
n=535000001=f(n)
n=535199981=f(n)
n=535199982=f(n)
n=535199983=f(n)
n=535199984=f(n)
n=535199985=f(n)
n=535199986=f(n)
n=535199987=f(n)
n=535199988=f(n)
n=535199989=f(n)
n=535199990=f(n)
n=535200000=f(n)
n=535200001=f(n)
n=1111111110=f(n)
f(1111111110) = 1111111110
Time elapsed(sec): 32.657