30.在从1到n的正数中1出现的次数
题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。
例如输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次。
分析:这是一道广为流传的google面试题。
最优美的算法就是按位进行分析
我们以21034来分析
如果将个位设为1,只考虑个位数上面的1,会有多少个1。(从1031->1021->1011->...->0001) 104个数包含104个1
如果将十位设为1,只考虑十位数上面的1,会有多少个1。(从101x->091x->...->001x)10*10个1,(x为0到9,不考虑个位上的1)
如果将百位设为1,只考虑百位数上面的1,会有多少个1。如果和刚才一样将百位设为1,发现千位只能为0,否则构成的数就比本身大了。
那么如果百位为0,将百位设为1,会有多少个1。(01xx),包含x个1,这时候的x为100。
如果将千位设为1,只考虑千位数上面的1,会有多少个1。这时候也比较特殊,因为千位本来就为1。那么不仅要考虑万位有多少个数,还要考虑百位、十位、个位上有多少数。
万位上只能是1,不能是2,如果为2,可能构成比本事大的数。那么千位为1,只考虑千位的1,会有多少1。
1000+34个(万位为1,三位数有一千种组合;万位为2,后面三位数不能大于原来的数,所以是34)
如果将万位设为1,只考虑万位数上面的1,会有多少个1。0个,因为不存在十万位。
综上所述:将N分为高位,当前位,低位,1的个数为count。
如果当前位为0,count应该加上高位的值*低位的位数。
如果当前位为1,count应该加上高位的值*低位的位数,再加上低位的个数(低位的数值+1)
如果当前位大于1,count应该加上高位的个数*低位的位数
如果不明白,根据代码分析
#include<iostream> #include<cstring> #include<stdio.h> #include<stack> using namespace std; int howMachOne(int n){ int count=0;//记录总共有多少个1 int factor=1;//记录低位的位数 int low;//记录低位的数值 int current;//记录当前位数的值 int hight;//记录高位的值 while(n/factor!=0){ low=n%factor; current=(n/factor)%10; hight=n/(factor*10); switch(current){ case 0: count+=hight*factor;//高位的值*低位的位数 break; case 1: count+=hight*factor+low+1;//高位的值*低位的个数+低位的个数 break; default: count+=(hight+1)*factor;//高位的个数*低位的位数 break; } factor*=10; } return count; } int main(){ int count=howMachOne(12); cout<<count<<endl; return 0; }