题目描述
给定一个十进制的正整数N,从1开始,到N的所有整数,然后数一下其中1出现的个数。
思路
当然,这个题从1列举到N可以求出来,但是时间复杂度达到O(n*lgn),同时也可以将这个看做一个数学问题。
先看看1位数的情况
如果N=4,那么从1到4所有的数字,1、2、3、4,只有个位上才有可能出现1,而且只是出现一次,所有当n>1时,f(n)=1。
2位数的情况
如果N=14,那么从1到14所有的数字,会发现个位和十位都有可能出现1,分开考虑,个位出现1的有1和11,十位出现1的有10、11、12、13、 14,所有f(n)=2+5=7。在比如24的情况,个位出现1只有1和11和21,十位出现1得有10到19,所有f(n)=3+10=13。
得出结论:如果N的个位数大于等于1,那么个位出现1的次数等于十位上的数+1(比如24个位出现3个1,那么等于十位2+1);如果个位为0的话,个位出现1的次数等于10位1出现的次数;如果十位上出现1,那么十位上1出现的次数等于个位上的数+1,(比如14,十位上出现了5个1,等于个位上得数4+1),如果个位数的数大于1,那么十位上出现1的次数为10。
f(4)=个位数的1+十位上的1 = 1
f(14)=个位的1+十位的1 = (个位大于1,个位出现的次数为十位+1为1+1=2)+(十位为1,那么十位上1出现的次数为个位数+1=4+1=5)=7
f(24)=个位数1+十位数1 = (个数大于1,类比,个位有3个1)+(十位数大于1,那么十位上出现1的次数为10) = 13
f(94)=个位出现的1+十位出现的1=(个位大于1,则出现1的个位为十位上的数+1=10)+(十位数大于1,那么出现1的个数为10)=20
推理到一般
若百位上的数字为0,那么百位数1出现的次数是由更高位决定的,比如12023,百位数出现1的次数是100~199、1100~1199、2100~2199…11100~11199一共是12*100=1200个
若百位数的数字为1,比如12113,那么除了高位的影响外还有低位的影响,高位是1200个,低位会出现12100…12113,等于(113)+1个。
若百位大于1,比如12213,则百位出现1的个数仅仅由更高位决定,(100~199、1100~1199、2100~2199、11100~11199、12100~12199)一共1300个,为(12+1)*100个。
public static int oneNumber(int n){
int icount = 0;
int ifactor = 1;
int iLowerNum = 0;
int iCurrNum = 0;
int iHigherNum = 0;
while(n/ifactor != 0){
iLowerNum = n - (n/ifactor)*ifactor;
iCurrNum = (n/ifactor)%10;
iHigherNum = n/(ifactor*10);
switch (iCurrNum) {
case 0:
icount += iHigherNum *ifactor;
break;
case 1:
icount += iHigherNum *ifactor +iLowerNum +1;
break;
default:
icount += (iHigherNum +1)*ifactor;
break;
}
ifactor *= 10;
}
return icount;
}