您的位置:首页 > Web前端

剑指Offer_43 1~n整数中1出现的次数

2018-03-05 21:45 405 查看
题目:
输入一个整数n,求1~n这n个整数的十进制表示中1出现的次数。例如,输入12,1~12这些整数中包括1的数字有1、10、11、12,1出现了5次。
提示:
假设我们输入21345,我们把其分为1-1345和1346-21345
第一步:求1346-21345中1出现的次数。
    1346-21345中,1出现在10000-19999中共10000次(10^4)。
值得注意的是,并不是对所有5位数而言在万位出现的次数是10000次。对于万位是1的数字如输入12345,1只出现在10000-12345的万位吗,出现的次数并不是10^4次,而是2346次,也就是除去最高位数字之后剩下数字+1(2345+1)。
第二步:接下来分析1出现在除最高位之外的其他4位数中的情况。1346-21345这20000个数字中后4位1出现的次数是8000次(firstNum*(length-1)*(10^(length-2)))。
由于最高位是2,我们可以再把1346-21345分为两段:1346-11345和11346-21345。每段剩下的4位数字中,选择其中一位是1,其余三位可以再0~9这10个数字中任意选择,因此为:2*4*10^3=8000;
第三步:至于1-1345中1出现的次数,就可以是递归实现了。这也是我们为什么要把1-21345和1-1345和1346-21345分两段的原因。因为把21345的最高位去掉就变成1345,便于我们采用递归。

分析:class Solution{
public static int numberOf1Between(int n){
//先将数字转为字符数组
if(n<=0) return 0;
char [] chs=String.valueOf(n).toCharArray();
return numberOf1(chs);
}
public static int numberOf1(char [] chs){
if(chs==null){
return 0;
}
int first=chs[0]-'0';
if(chs.length==1&&first==0){
return 0;
}
if(chs.length==1&&first>0){
return 1;
}

//假设strN是“21345”
//numFirstDigit是数字10000-19999的第一位中的数目
int numberFirstDigit=0;
if(first>1){
//说明存在1的为10^length-1
numberFirstDigit=powOf10(chs.length-1);
}else if(first==1){
//截取先的数组+1,例如2345+1=2346
numberFirstDigit= Arrays.copyOfRange(chs,1,chs.length)[0]-'0'+1;
}

//numOtherDigits是1346-21346除第一位以外的数目
int numOtherDigits=first*(chs.length-1)*powOf10(chs.length-2);
//numRecursive是1-1345中的数目,数组后面首地址+1,递归查找1~1345的,类似1-345和346-1345
int numRecursive=numberOf1(Arrays.copyOfRange(chs,1,chs.length));

return numberFirstDigit+numOtherDigits+numRecursive;

}
//求10的次方
public static int powOf10(int length){
if(length==0) return 1;
int res=1;
for(int i=0;i<length;i++){
res*=10;
}
return res;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: