43. 从 1 到 n 整数中 1 出现的次数

整数中1出现的次数(从1到n整数中1出现的次数)

http://www.nowcoder.com/questionTerminal/bd7f978302044eee894445e244c7eee6

public int NumberOf1Between1AndN_Solution(int n) {
    int cnt = 0;
    for (int m = 1; m <= n; m *= 10) {
        int a = n / m, b = n % m;
        cnt += (a + 8) / 10 * m + (a % 10 == 1 ? b + 1 : 0);
    }
    return cnt;
}
思路是分别计算个位、十位、百位........上出现 1 的个数。
以  n =216为例:
个位上: 1 ,11,21,31,.....211。个位上共出现(216/10)+ 1个 1 。因为除法取整,210~216间个位上的1取不到,所以我们加8进位。你可能说为什么不加9,n=211怎么办,这里把最后取到的个位数为1的单独考虑,先往下看。
十位上:10~19,110~119,210~216.   十位上可看成 求(216/10)=21 个位上的1的个数然后乘10。这里再次把最后取到的十位数为1的单独拿出来,即210~216要单独考虑 ,个数为(216%10)+1 .这里加8就避免了判断的过程。
后面以此类推。
时间复杂度 O(logN)

感谢大家的点赞,其实这种算法能讲的更清楚,但本人比较菜,也懒得去花时间具体讲了,推荐大家一个回答,易懂,高效



全部评论
很巧妙,就是我看的有点懵
2 回复 分享
发布于 2020-03-23 21:05
cnt += ( a/10 +(a%10>1 ?1:0) )* m + (a % 10 == 1 ? b + 1 : 0);换成这句更好更有逻辑
2 回复 分享
发布于 2020-05-19 21:09
看懵了带我一个。。。得思考一下
1 回复 分享
发布于 2020-03-24 11:43
此解法有缺陷,当n过大时,会产生溢出。 当n=1410065412,cnt-1993108826 因为int的最大值2147483647,有十位。当m的位数达到10,如果继续乘以10,m就会溢出,导致结果出错。
1 回复 分享
发布于 2020-07-30 16:27
举例说明:以216为例,注意216是一个相当特殊的数字,从1到216这216个数中,个位是1的情况有1 11 21 31 41 51 .... 211 ,(注意这个11,这里虽然出现了两个1,但是下一步固定十位为1的时候会考虑到)这里一共有1~21=21 +1(001种) 也就是216/10+1;然后是十位数,11,12,13,14,15...19;(10个) 110,111,112,113...119;(10个) 210,211,212...216(6+1,加1是因为0到6) 这里我们发现,从1到216这216个数中,固定十位数为1的情况有 10*2+6+1,想到这里,我们应该能够理解为什么需要把216这个数字拆分成a=n/m和b=n%m了,因为我们需要单独考虑210到216这7个数,此时(考虑10位数的时候)除了a/2(其实就是百位数)*10=20以外,还要加上b+1;假如n不是216,而是206,则取不到210到216这7个数,假如n是226,则会取到210到219这10个数,由此可见,只有a的末位为1时才需要考虑取不满m个的情况,故a % 10 == 1时,要加上b+1;再考虑n=226的情况,此时由于可以取到210到219这10个数,所以固定十位数为1的情况有(a/10+1)*10;那n=236呢?也是(a/10+1)*10,接着往后想一直到306,都是30,而316是30+7,据此可以判断,只有0/1是特殊的,在程序实现中这么处理这个特殊呢?可以加一个判断,或者用a+8避免这个判断,之所以是+8,通过上面的分析很明显可以理解,是因为当a的次低位为0或者1时,a/10==(a+8)/10,当a的次低位>=2,补8会产生进位位,效果等同于(a/10+1)
8 回复 分享
发布于 2020-04-13 17:56
有没有人能稍微解释一下,看得有点懵
点赞 回复 分享
发布于 2020-04-08 11:26
有点明白,但感觉还有点迷糊,我只能先献上自己的膝盖,大佬NB!!!!!
点赞 回复 分享
发布于 2020-04-26 15:56
你这个算法测一个11,得出来是4个1,因为你重复统计了11这个数两次
点赞 回复 分享
发布于 2020-05-02 08:38
虽然思路不难理解,但我就是想不到,这就是和大佬的差距了。
点赞 回复 分享
发布于 2020-05-21 04:18
你这是在数据连续的情况下可以,不连续就不能了吧,不具有普遍性。
点赞 回复 分享
发布于 2020-07-29 11:15
如:n=216 m a=n/m b=n%m (a+8)/10*m+(a%10==1?b+1:0) 1 216 0 22*1+0(X1,其中X∈[0, 21]。即001、011、...、211) 10 21 6 2*10+7(X1Y,其中X∈[0, 1]时,Y∈[0, 9];X∈{2}时,Y∈[0, 6]。即01X,11X,210,...,216) 100 2 16 1*100+0(1X,其中X∈[0, 99]。即100,101,...,199)
点赞 回复 分享
发布于 2021-04-21 09:23
大佬NB!!!a+9也可以,只要把多计算了的减去,if(a%10 == 1) cnt -= m-1-b; //\n例如216计算十位时减去3(10-1-6=3,减去217、218、219)。
点赞 回复 分享
发布于 2021-11-11 21:42

相关推荐

01-07 15:50
四川大学 Java
看日出看日落:好好背八股,做算法。我身边跟你bg差不多的基本都大厂暑期
点赞 评论 收藏
分享
EEbond:给北邮✌️跪了
点赞 评论 收藏
分享
评论
147
4
分享

创作者周榜

更多
牛客网
牛客企业服务