整数中1出现的次数(从1到n整数中1出现的次数)
题目描述
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
解析
遍历一遍不就完了吗
当然,你可从1遍历到n,然后将当前被遍历的到的数中1出现的次数累加到结果中可以很容易地写出如下代码:
public int NumberOf1Between1AndN_Solution(int n) {
if(n < 1){
return 0;
}
int res = 0;
for(int i = 1 ; i <= n ; i++){
res += count(i);
}
return res;
}
public int count(int n){
int count = 0;
while(n != 0){
//取个位
count = (n % 10 == 1) ? ++count : count;
//去掉个位
n /= 10;
}
return count;
}
但n多大就会循环多少次,这并不是面试官所期待的,这时我们就需要找规律看是否有捷径可走
不用数我也知道
以 51234
这个数为例,我们可以先将 51234
划分成 1~1234
(去掉最高位)和 1235~51234
两部分来求解。下面先分析 1235~51234
这个区间的结果:
所有的数中,1在最高位(万位)出现的次数
对于
1235~51234
,最高位为1时(即万位为1时)的数有10000~19999
这10000个数,也就是说1在最高位(万位)出现的次数为10000,因此我们可以得出结论:如果最高位大于1,那么在最高位上1出现的次数为最高位对应的单位(本例中为一万次);但如果最高位为1,比如1235~11234
,那么次数就为去掉最高位之后的数了,11234
去掉最高位后是1234
,即1在最高位上出现的次数为1234
所有的数中,1在非最高位上出现的次数
我们可以进一步将
1235~51234
按照最高位的单位划分成4个区间(能划分成几个区间由最高位上的数决定,这里最高位为5,所以能划分5个大小为一万子区间):
1235~11234
11235~21234
21235~31234
31235~41234
41235~51234
而每个数不考虑万位(因为1在万位出现的总次数在步骤1中已统计好了),其余四位(个、十、百、千)取一位放1(比如千位),剩下的3位从
0~9
中任意选(10*10*10
),那么仅统计1在千位上出现的次数之和就是:5(子区间数)*10*10*10
,还有百位、十位、个位,结果为:4*10*10*10*5
。因此非高位上1出现的总次数的计算通式为:
(n-1)*10^(n-2)*十进制最高位上的数
(其中n
为十进制的总位数)于是
1235~51234
之间所有的数的所有的位上1出现的次数的综合我们就计算出来了
剩下 1~1234
,你会发现这与 1~51234
的问题是一样的,因此可以做递归处理,即子过程也会将 1~1234
也分成 1~234
和 235~1234
两部分,并计算 235~1234
而将 1~234
又进行递归处理。
而递归的终止条件如下:
如果
1~n
中的n
:1<=n<=9
,那么就可以直接返回1了,因为只有数1出现了一次1如果
n==0
,比如将10000
划分成的两部分是0~0(10000去掉最高位后的结果)
和1~10000
,那么就返回0
public int NumberOf1Between1AndN_Solution(int n) {
if(n < 1){
return 0;
}
return process(n);
}
public int process(int n){
if(n == 0){
return 0;
}
if(n < 10 && n > 0){
return 1;
}
int res = 0;
//得到十进制位数
int bitCount = bitCount(n);
//十进制最高位上的数
int highestBit = numOfBit(n, bitCount);
//1、统计最高位为1时,共有多少个数
if(highestBit > 1){
res += powerOf10(bitCount - 1);
}else{
//highestBit == 1
res += n - powerOf10(bitCount - 1) + 1;
}
//2、统计其它位为1的情况
res += powerOf10(bitCount - 2) * (bitCount - 1) * highestBit;
//3、剩下的部分交给递归
res += process(n % powerOf10(bitCount - 1));
return res;
}
//返回10的n次方
public int powerOf10(int n){
if(n == 0){
return 1;
}
boolean minus = false;
if(n < 0){
n = -n;
minus = true;
}
int res = 1;
for(int i = 1 ; i <= n ; i++){
res *= 10;
}
return minus ? 1 / res : res;
}
public int bitCount(int n){
int count = 1;
while((n /= 10) != 0){
count++;
}
return count;
}
public int numOfBit(int n, int bit){
while(bit-- > 1){
n /= 10;
}
return n % 10;
}
笔者曾纠结,对于一个四位数,每个位上出现1时都统计了一遍会不会有重复,比如 11111
这个数在最高位为1时的 10000~19999
统计了一遍,在统计非最高位的其他位上为1时又统计了4次,总共被统计了5次,而这个数1出现的次数也确实是5次,因此没有重复。
出自:http://www.zhenganwen.top
已获授权