剑指offer 整数中1出现的次数(从1到n整数中1出现的次数)
求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
解题思路
这个题是有一定规律的,我们可以计算从1~n中个位会出现1的情况有多少种,百位出现1的情况有多少种,以此类推,这个很容易实现,for循环中变量每次10就可以。
我们假设现在的n是325,个位为1的情况有多少种,321,311,301,291。。。等等,这个时候我们可以将325分开两部分,思考一下个位为1,是不是就是个位之前的数字变化,我们这里先只考虑n的个位是大于1的情况,所以一共有n/10+1,如果n是320的话,那么1出现的次数就是n/10,因为个位特殊所以他是大于1还是等于1都是一样的,如果是考虑十位为1的情况,假设这时的n为314,十位为1的情况有314,313,312,311,310,219,218,217。。。从219以后就是十个一组,但是314-310是5个所以要分开算,这时候我们将n分为两半,当查询十位1的情况时,
a=n/10;b=n%10,假设这个时候n=325,a=32,b=5,由于十位是2大于1,所以就是32/10+1=4,然后410=40个,310~319,210 ~219,110 ~119 ,10 ~19。由于十位是大于0 的就不用考虑其他的情况了,如果这时的n=317,a=31,b=7,因为此时的十为等于1,所以要考虑不全的情况,31/10*10=30个,然后再算不全的情况,b+1=5+1,310 ~315 ,6个,所以有6个,以此类推。。
n | a | b | |
---|---|---|---|
3125 | 3125/1=3125 | 0 | |
3125 | 3125/10=312 | 5 | |
3125 | 3125/100=31 | 25 | |
3125 | 3125/1000=3 | 125 |
这里我也是参考了别人的文档,+8的问题,假设n=325,十位为2,这个时候十位为1的情况有40个,所以(a+8)/1010=40个,直接进位了,假设这个时候n=315,1+8<10所以不会进位,所以(a+8)/1010=30,因为这个时候十位是1,所以要考虑不全的情况。(a%10==1)*(b+1),如果十位为1就加上b+1,不用考虑十位为0的情况,为0不会出现一的情况,所以只考虑大于1和等于1就可以
代码
public class Solution {
public int NumberOf1Between1AndN_Solution(int n) {
int count = 0;
for (long j = 1; j <= n; j *= 10) {
count+=((n/j)+8)/10*j + (n/j % 10 == 1 ? 1 : 0)*(n%j+1);
}
return count;
}
}