您的位置:首页 > 职场人生

Google 的一道面试题的解法

2006-11-02 16:33 555 查看
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?
有一个整数n,写一个函数f(n),返回0到n之间出现的"1"的个数。比如f(13)=6,现在f(1)=1,问下一个最大的f(n)=n的n是什么?
为什么f(13)=6, 因为1,2,3,4,5,6,7,8,9,10,11,12,13.数数1的个数,正好是6.
程序一【未经过优化,效率低的惊人】
#include <windows.h>
main()
{
int i,begin,end,temp=0,num=0;
begin=GetTickCount();
for(i=1;i<1111111110;i++)
{
temp=i;
while(temp)
{
if(temp%10==1)num++;
temp=temp/10;
}
if(num==i) printf("f(%d)=%d/n",i,num);
}
end=GetTickCount();
end-=begin;
printf("time: %d ms/n",end);
system("pause");
}

程序二:【稍微经过优化的算法,不过效率也不高吆】
#include <windows.h>
main()
{
int i,begin,end,temp=0,num=0,num1,num2;
int Number[1000];
begin=GetTickCount();
for(i=0;i<1000;i++)
{
temp=i;
while(temp)
{
if(temp%10==1)num++;
temp=temp/10;
}
Number[i] = num;
num = 0;
}
num = 0;
for(i=0;i<1111111111;i++)
{
temp=i;
while(temp)
{
num1 = temp/1000;
num2 = temp - num1*1000;
num += Number[num2];
temp = num1;
}
if(num==i) printf("f(%d)=%d/n",i,num);
}
end=GetTickCount();
end-=begin;
printf("time: %d ms/n",end);
system("pause");
}

程序三:【优化后的算法,效率明显的提高】
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>

int f(int n);
int count1(int n);
int cal(unsigned int number,int nwei,int count1,unsigned int ncount);
int gTable[10];
const unsigned int gMAX = 4000000000L;
int main(int argc, char* argv[])
{
int i;
unsigned int n=1;
unsigned int ncount = 0;
int nwei = 0;
int ncount1;
int beginTime=GetTickCount();
//init gTable
for(i=0;i<10;++i)
{
n *= 10;
gTable[i] = f(n-1);
}
n=0;
nwei = 0;
ncount1 = 0;
while(n<gMAX)
{
unsigned int temp;
temp = 1;
ncount =cal(n,nwei,ncount1,ncount);
for(i=0;i<nwei;++i)
temp *= 10;
n += temp;
if( (n/temp)/10 == 1)
++nwei;
ncount1 = count1(n);
}
int endTime=GetTickCount();
endTime-=beginTime;
printf("time: %d ms/n",endTime);
system("pause");
return 0;
}
int f(int n)
{
int ret = 0;
int ntemp=n;
int ntemp2=1;
int i=1;
while(ntemp)
{
ret += (((ntemp-1)/10)+1) * i;
if( (ntemp%10) == 1 )
{
ret -= i;
ret += ntemp2;
}
ntemp = ntemp/10;
i*=10;
ntemp2 = n%i+1;
}
return ret;
}
int count1(int n)
{
int count = 0;
while(n)
{
if( (n%10) == 1)
++count;
n /= 10;
}
return count;
}
int cal(unsigned int number,int nwei,int count1,unsigned int ncount)
{
int i,n=1;
unsigned int maxcount;
if(nwei==0)
{
ncount += count1;
if(number == ncount)
{
printf("f(%d) = %d /n",number,number);
}
return ncount;
}
for(i=0;i<nwei;++i)
n *= 10;
maxcount = ncount + gTable[nwei-1];
maxcount += count1*n;
if(ncount > (number + (n-1)) )
{
return maxcount;
}
if(maxcount < number)
{
return maxcount;
}
n /= 10;
for(i=0;i<10;++i)
{
if(i==1)
ncount = cal(number+i*n,nwei-1,count1+1,ncount);
else
ncount = cal(number+i*n,nwei-1,count1,ncount);
}
return ncount;
}
程序四【另类解法,提供一个思路,不过效率是个问题吆】
/*
粗略的看上去以为需要逐位通过某种规则去求解,可是仔细一想,是否可以这么考虑。
一个数字:xyz,从1数到他需要1,2,3,。。。,xyz
转换一个思路,那么就是001,002,003,。。。,xyz
因为我们要计数的是1出现的次数,加上0并不影响结果。
如果这个数是999999,即一个全部由9组成得数字,那么之间经过的数中,0出现几率1/10,1出现几率是1/10,,,,9出现几率是1/10。
再扩展一下,一个数x999999,即除第一位外都由9组成,那么1出现的次数就是(x99999+1)×(1/x)+后面的位数×(x99999+1)×(1/10) 也就是说最高位出现1的可能性就是最高位的倒数,其他各位出现0-9的几率都是相等的。
那 么现在如果有一个数,我们就可以先求得小于本身最接近的x999999这样的数,那么从0-这个x999999数的1出现的次数可以直接用上面的公式求 的,然后(本身-x9999999)这个数再求从0到他出现的1个个数就可以了。(当然这个还得考虑最高位是否为1的特殊情况)
*/
#include <stdio.h>
int countones(int number)
{
if(number<10)
return number==0?0:1;
int result=0;
int base=10;
int count=0;
while(number/base!=0)
{
base*=10;
count++;
}
base=base/10;
int highbit=(int)(number/base);
int x=count*base/10;
result+=(highbit==1)?x:base+x*highbit;
int left=number%base;
int temp=countones(left);
if(highbit==1)
{
result+=left+1;
}
result+=temp;
return result;
}

main()
{
int i;
for(i=0;i<1111111111;i++)
{
if(countones(i)==i)printf("f(%d)=%d/n",i,countones(i));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: