整数中1出现的次数

题目描述

输入一个整数n,求1n这n个整数的十进制表示中1出现的次数。例如,输入12,112这些整数中包含1的数字有1、10、11和12,1一共出现了5次。

解法一:

遍历所有的数字,不停地将数字i%10,i/10,求得每个数字含有1的个数。每个数字i有logi位,所以时间复杂度为O(nlogn)。效率很慢,不推荐。

解法二:

观察数字规律。
假如n=23,即序列为1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23
1-9中共有1个1,
10-19中每个数字的开头都有1,如果不考虑开头的1,则变为求0-9中1的个数,与1-9中1的个数相同。10-19一共10个数字,算上每个开头都有的1,加上0-9中1的个数,一共有11个1,
20-23中每个数字的开头为2,可以不考虑,则变为求0-3中1的个数,则20-23中共1个1
所以1-19中共有13个1。
由此我们可以看出,位数更多的数是由位数更低的数组成的,以1-20为例,
我们只需要知道含有多少组0-9,(为了与10之类的低位0符合,采用0~9而不是1-9),也即各位为1的数量,则序列退化为0,0,0,0,0,0,0,0,0,0,10,10,10,10,10,10,10,10,10,10,20,20,20,20,
再统计有多少组10即可,也即十位为1的数量。
可以推而广之,知道任何一位1的数量,最后相加即可得到1的总数量。
个位1的数量,我们可以计算n/10的值i1,n%10的值y1,若y1>=1,则s1=i1+1,若y1=0,则s1=i1
十位1的数量,我们可以计算n/100的值i2,n%100的值y2,若y2>=20,则s2=i2 * 10+10,若10<=y2<20,则s2=i2 * 10 + y2 % 10 + 1,若0<=y2<10,则s2=i2 * 10
百位1的数量,我们可以计算n/1000的值i3,n%1000的值y3,若y3>=200,则s3=i3 * 100 + 100,若100<=y3<200,则s3=i2 * 100 + y3 % 100 + 1, 若0<=y3<100,则s3=i3 * 100
……
……
所以个位1的数量也可以写成
个位1的数量,我们可以计算n/10的值i1,n%10的值y1,若y1>=2,则s1=i1 * 1 + 1,若1<=y1<2,则s1=i1 * 1 + y1 % 1 + 1,若0<=y1<1,则s1=i1*1
于是可以通过循环很简单来实现,时间复杂度为O(logn)

public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        int num = n;
        int divisor = 1;
        int sum = 0;
        while(num / 10.0 > 0) {
            int i = n / (divisor * 10);
            int y = n % (divisor * 10);
            if(y >=  2 * divisor) {
                sum += i * divisor + divisor;
            }
            else if(y >= divisor && y < 2 * divisor){
                sum += i * divisor + y % divisor + 1;
            }
            else {
                sum += i * divisor;
            }
            divisor *= 10;
            num /= 10;
        }
        return sum;
    }
}

注意循环条件为num/10.0而不是num/10,这是为了保证只有个位数的情况。

你可能感兴趣的:(整数中1出现的次数)