Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.
For example:
Given n = 13,
Return 6, because digit 1 occurred in the following numbers: 1, 10, 11, 12, 13.
显然不能依次计算每个0--n中每个数中1出现的个数。所以需要去找规律。
对于0--n中1出现的次数可以分成三部分考虑。假设n为digit位数。
第一部分:对于digit位数,统计1出现在最高位的情况。如果最高位大于1,则可能有10的n-1次方个,比如2345,1出现在最高位的四位数字有1000个,如果n==1则有后面的数字加1个,比如1234,1出现在最高位的四位数字有235个;
第二部分:对于digit位数,统计1出现在其他位上的情况。那么需要固定首位first为1--first,在后面digit-1位中选定一个位置为1,其他digit位-2可以任选数字,则first*(digit-1)*10^(digit-2)
第三部分就是计算digit-1位数。
/**
* 显然不能依次计算每个0--n中每个数中1出现的个数。所以需要去找规律。
* 对于0--n中1出现的次数可以分成三部分考虑。假设n为digit位数。
* 第一部分:对于digit位数,统计1出现在最高位的情况。如果最高位大于1,则可能有10的n-1次方个,比如2345,1出现在最高位的四位数字有1000个,如果n==1则有后面的数字加1个,比如1234,1出现在最高位的四位数字有235个;
* 第二部分:对于digit位数,统计1出现在其他位上的情况。那么需要固定首位first为1--first,在后面digit-1位中选定一个位置为1,其他digit位-2可以任选数字,则first*(digit-1)*10^(digit-2)
* 第三部分就是计算digit-1位数。
*/
public int countDigitOne(int n) {
int resultNum = 0;
if(n<=0){
return 0;
}
/*个位数返回1出现的次数为1*/
if(n<=9){
return 1;
}
/*把这个数转化为长度字符数组*/
String s = n+"";
char[] arr = s.toCharArray();
int digit = arr.length;
/*计算首位的值*/
int first = arr[0] - '0';
/*计算除了首位之后的整数值:1345*/
int other = getInteger(arr,1);
/*计算去掉首位时剩下的n-1位中1出现的次数 递归计算1345*/
int numerOfn1 = countDigitOne(other);
/*计算首位为1的n位整数中1出现的次数*/
int numerFirst1 = 0;
if(first==1){
numerFirst1 = other+1;//如12345中1在首位的五位数中出现的数字有2346个。
}else{//对于首位不为1的len位数来说,1在首位出现的数字有10的(len-1)次方
numerFirst1 = getPower10(digit-1);
}
/*计算首位不为1的n位整数中1出现的次数,1346 ~ 21345除了第一位为1的情况
* 对于这种情况来说,对于后面的(len-1)位,任意一位固定为1,则其他为可任选,则有(len-1)*(10的(len-1)次方),最后再乘以首位数字。
*/
int numerFirstN1 = first*(digit-1)*getPower10(digit-2);
/*汇总*/
resultNum = numerOfn1 + numerFirst1 + numerFirstN1;
return resultNum;
}
/**
* 把数组arr[index]之后的字符组成整数。
*/
int getInteger(char[] arr,int index){
int re = 0;
int len = arr.length;
for(int i=index;i<len;i++){
re = re*10 + arr[i]-'0';
}
return re;
}
/**
* 计算10的ex次方。
*/
int getPower10(int ex){
int re = 1;
for(int i=0;i<ex;i++){
re = re*10;
}
return re;
}