各大计算机公司 笔试及面试 题目 - Google (在从1到n的正数中1出现的次数)

在从1到n的正数中1出现的次数(数组)


题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。例如输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次。

分析:这是一道广为流传的google面试题。


#include <iostream>
#include <fstream>
#include<iomanip>

#include<climits>
#include<ctime>
#include<cstdio>
#include<math.h>

using namespace std;

/****************************************************************
*
*方法一
* 上午花了差不多一上午的时间想出来的一个方法,经过测试之后发现比目前网上流传
* 的方法速度更快。
*
* 如果需要转载本方法,请注明来源,谢谢。
*
*****************************************************************/
int numOfOne(unsigned int ia )
{
	unsigned int idigit=ia;
	unsigned int iremainder=0; //当前正在处理的数
	unsigned int i10s=1;

	unsigned int tmpleft=0;   //iremainder 的左边的数值
	unsigned int tmpright=0;  //iremainder 的右边的数值


	unsigned int sum=0;

	while(idigit)
	{
		iremainder=idigit%10;
		idigit /=10;

		tmpleft = ia/i10s;
		tmpleft /=10;

		tmpright = ia%(i10s);

		if(iremainder>1)
		{
			tmpleft+=1;
			sum+=tmpleft*(i10s);
		}
		else if(iremainder==1)
		{
			sum+= tmpleft*(i10s)+(tmpright+1); //关键点
			
		}
		else if(iremainder==0)
		{
			sum+=tmpleft*(i10s); 
		}

		i10s *=10;
	}

	return sum;

}

/****************************************************************
*
*方法二 (网上流传的方法)
*
*****************************************************************/

int numOfOne_2(unsigned int n)
{
     unsigned int number = 0;
	 unsigned int j=0;
     
      for(unsigned int i = 1; i <= n; ++ i)
	  {
		j=i;
		while(j)
		{
            if(j % 10 == 1)
                  number++;

            j = j / 10;
       }
	 }
     return number;
}

/****************************************************************
*
*方法三 (网上流传的方法)
*
*****************************************************************/

char num[16];
int len, dp[16][16][2];

int dfs(int pos, int ct, int less)
{
 if (pos == len)
    return ct;

 int &ret = dp[pos][ct][less];
 if (ret != -1)
	 return ret;

 ret = 0;
 for (int d = 0; d <= (less ? 9 : num[pos] - '0'); d++)
	ret += dfs(pos + 1, ct + (d == 1), less || d < num[pos] - '0');

 return ret;
}

int numOfOne_3(unsigned int n)
{
 sprintf(num, "%u", n);
 len = strlen(num);
 memset(dp, 0xff, sizeof(dp));
 return dfs(0, 0, 0);
}


/****************************************************************
*
*测试
*
*****************************************************************/


int main(int agrc, char** argv)
{
	unsigned int sum=0,sum2=0,sum3=0;

	clock_t ctbegin,ct2begin,ct3begin;
	clock_t ctend,ct2end,ct3end;
	clock_t diff=0,diff2=0,diff3=0;

	int imax=numeric_limits<int>::max();
		
	unsigned int iumax=numeric_limits<unsigned int>::max();
	
	
	ofstream ofs("test_google_0912.txt");

	for(unsigned int i=0;i<1000000;i++)
	{
		// 方法一 测试
		ctbegin=clock();
		sum=numOfOne(i);
	    ctend=clock();
		diff=ctend-ctbegin;

		// 方法二 测试
		//ct2begin=clock();
		//sum2=numOfOne_2(i);
		//ct2end=clock();
		//diff2=ct2end-ct2begin;

		// 方法三 测试
		ct3begin=clock();
		sum3=numOfOne_3(i);
		ct3end=clock();
		diff3=ct3end-ct3begin;
				
		//cout<<"i="<<setw(5)<<right<<i<<" : "<<sum <<" ("<<diff<<")" <<" | "<<sum2<<" ("<<diff2<<") ";
		
		//ofs<<"i="<<setw(5)<<right<<i<<" : ";
		//ofs<<setw(10)<<sum <<" ("<<setw(3)<<diff <<") " ;
		//ofs<<setw(10)<<sum2<<" ("<<setw(3)<<diff2<<") ";
		//ofs<<setw(10)<<sum3<<" ("<<setw(3)<<diff3<<") ";
		//ofs<<endl;

		//if( (sum !=sum2) || (sum !=sum3))
		if( sum !=sum3)
		{
			cout<<"i="<<setw(5)<<right<<i<<" : "<<sum <<" | "<<sum2<<" | "<<sum3<<" ";
			cout<<" X "<<endl;
		}

		if(diff !=diff3)
		{
			ofs<<"i="<<setw(5)<<right<<i<<" : ";
			ofs<<setw(10)<<sum <<" ("<<setw(3)<<diff <<") " ;
			ofs<<setw(10)<<sum3<<" ("<<setw(3)<<diff3<<") ";
			ofs<<endl;
		}

	}
 
}


测试结果如下:(第二列和第三列中的数字为 1的个数,括号内的为计算时间,单位为毫秒,测试工具 VS2010。

测试值          方法一(毫秒)  方法三(毫秒)

i= 1806 :       1368 (  0)       1368 ( 16) 
i= 3242 :       2055 (  0)       2055 ( 15) 
……


i=14305 :      10667 (  0)      10667 ( 16) 
i=15392 :      12073 (  0)      12073 ( 16) 
i=16497 :      13498 (  0)      13498 ( 15) 
……
i=31171 :      22582 (  0)      22582 ( 15) 
i=32201 :      23741 (  0)      23741 ( 16) 
i=33195 :      24036 (  0)      24036 ( 15) 

……
i=44826 :      28473 (  0)      28473 ( 15) 
i=45839 :      28774 (  0)      28774 ( 47) 
……
i=65738 :      36754 (  0)      36754 ( 16) 
i=66734 :      37054 (  0)      37054 ( 15) 
i=67687 :      37339 (  0)      37339 ( 16) 
i=68671 :      37638 (  0)      37638 ( 16) 

……
i=79100 :      41721 (  0)      41721 ( 47) 
i=80042 :      42015 (  0)      42015 ( 16) 
i=81075 :      42394 (  0)      42394 ( 46) 
……
i=98890 :      49679 (  0)      49679 ( 15) 
i=99863 :      49977 (  0)      49977 ( 16) 
i=100804 :      51066 (  0)      51066 ( 15) 
i=101670 :      52879 (  0)      52879 ( 16) 
i=102635 :      54470 (  0)      54470 ( 16) 
i=103568 :      55686 (  0)      55686 ( 15) 
i=104525 :      56939 (  0)      56939 ( 16) 
……
i=123385 :      93465 (  0)      93465 ( 16) 
i=124208 :      94550 (  0)      94550 ( 15) 
i=124994 :      95495 (  0)      95495 ( 16) 
i=125819 :      96592 (  0)      96592 ( 16) 
i=126555 :      97572 (  0)      97572 ( 15) 
i=127352 :      98629 (  0)      98629 ( 16) 
……
i=877849 :     541375 (  0)     541375 ( 15) 
i=878547 :     541615 (  0)     541615 ( 16) 
i=879271 :     541858 (  0)     541858 ( 16) 

……
i=883309 :     544061 (  0)     544061 ( 15) 
i=884067 :     544217 ( 16)     544217 (  0) 

……
i=897707 :     549341 (  0)     549341 ( 16) 
i=898397 :     549580 (  0)     549580 ( 15) 
i=899119 :     549752 (  0)     549752 ( 16) 
i=899776 :     549958 (  0)     549958 ( 16) 

……
i=907950 :     553395 (  0)     553395 ( 15) 
i=908690 :     553639 (  0)     553639 ( 16) 
i=909457 :     553896 (  0)     553896 ( 16) 

……
i=923789 :     570159 (  0)     570159 ( 15) 
i=924512 :     570405 (  0)     570405 ( 16) 
i=925280 :     570658 (  0)     570658 ( 15)

 ……


i=951173 :     580586 (  0)     580586 ( 32) 
i=951913 :     581500 (  0)     581500 ( 15) 
i=952687 :     581839 (  0)     581839 ( 16) 
i=952967 :     581897 (  0)     581897 ( 15) 

……
i=966436 :     586994 (  0)     586994 ( 16) 
i=966621 :     587033 (  0)     587033 ( 15) 
i=967364 :     587277 (  0)     587277 ( 16) 

……
i=992891 :     597880 ( 16)     597880 (  0) 
i=993604 :     598121 (  0)     598121 ( 15) 
i=994162 :     598300 (  0)     598300 ( 16) 

……
i=999220 :     599852 (  0)     599852 ( 15) 
i=999921 :     599993 (  0)     599993 ( 16) 


用于测试的最大正整数为 :numeric_limits<unsigned int>::max() ,其值为:4294967295,1的个数为:642019964。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值