剑指offer_整数中1出现的次数

本文介绍了一种高效的算法,用于计算从1到n之间的所有整数中数字1出现的总次数。该算法通过巧妙地利用数学分析,将时间复杂度降低到了O(log n),并提供了详细的解释和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

求1~n的数字中,数字1出现的次数。

最无脑的做法,从1遍历到n,累计每个数字中1出现的次数。。。。
在leetcode上看到最牛逼的做法
先上代码再说:

public int countDigitOne(int n) {
    int ones = 0;
    for (long m = 1; m <= n; m *= 10)
        ones += (n/m + 8) / 10 * m + (n/m % 10 == 1 ? n%m + 1 : 0);
    return ones;
}

就是这么简洁!!!

时间复杂度达到了O(lgn)!!!

看一下leetcode上面大神的解释:

https://discuss.leetcode.com/topic/18054/4-lines-o-log-n-c-java-python

For each position, split the decimal representation into two parts, for example split n=3141592 into a=31415 and b=92 when we’re at m=100 for analyzing the hundreds-digit. And then we know that the hundreds-digit of n is 1 for prefixes “” to “3141”, i.e., 3142 times. Each of those times is a streak, though. Because it’s the hundreds-digit, each streak is 100 long. So (a / 10 + 1) * 100 times, the hundreds-digit is 1.

Consider the thousands-digit, i.e., when m=1000. Then a=3141 and b=592. The thousands-digit is 1 for prefixes “” to “314”, so 315 times. And each time is a streak of 1000 numbers. However, since the thousands-digit is a 1, the very last streak isn’t 1000 numbers but only 593 numbers, for the suffixes “000” to “592”. So (a / 10 * 1000) + (b + 1) times, the thousands-digit is 1.

The case distincton between the current digit/position being 0, 1 and >=2 can easily be done in one expression. With (a + 8) / 10 you get the number of full streaks, and a % 10 == 1 tells you whether to add a partial streak.

根本在于利用数学对数字的分析,直接推出了简洁的数学公式。

在苏宁的笔试中,遇到过这么一道题,n个人中有m对好友(两两称为一对),朋友的朋友都算是同一个朋友圈。问有多少个朋友圈。

咋一看,毫无头绪,其实也是道数学题。
m>n时,只有1个朋友圈;
m<n时,有n-m个朋友圈
就是这么简单。。。。。。。。。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值