题目:
数出0到n(含)中数字2出现了几次。
思路:
1、暴力方法,数出每个数字包含几个2,然后累加起来。
2、分析:分别考虑数字n每一位出现2的次数,如123123;
从左往右考虑4123123;
考虑第一个1(即第6位),该位出现2的次数为4*10^6/10;
考虑第一个2(即第5位),该位出现2的次数为41*10^5/10+3123+1;
考虑第一个3(即第4位),该位出现2的次数为(412+1)*10^4/10;
附:除以10的原因在于:每10个数字,任意位出现2的概率为1/10.
总结规律:
第i位出现2个次数与该位所在的数字有关:
当第i位的数字小于2,出现次数就等于比其高位部分的数字*10^i/10,
当第i位的数字等于2,出现次数就等于比其高位部分的数字*10^i/10+n%(10^i),
当第i位的数字大于2,出现次数就等于(比其高位部分的数字+1)*10^i/10。
代码:
#include<iostream> #include<sstream> #include<math.h> using namespace std; template<class out_T,class in_T> out_T convert(const in_T &t){ stringstream ss; out_T result; ss<<t; ss>>result; return result; } int count2sInRangeAtDigit(int number,int d){ int powerOf10=pow(10,d); int nextPowerOf10=powerOf10*10; int right=number%powerOf10; int roundDown=number-number%nextPowerOf10; int roundUp=roundDown+nextPowerOf10; int digit=(number/powerOf10)%10; if(digit<2) return roundDown/10; else if(digit==2) return roundDown/10+right+1; else return roundUp/10; } int count2sInRange(int number){ int count=0; string str; str=convert<string>(number); int len=str.size(); for(int digit=0;digit<len;digit++) count+=count2sInRangeAtDigit(number,digit); return count; } int main(){ int n; while(cin>>n){ cout<<count2sInRange(n)<<endl; } return 0; }