在从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。