一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情。
一、问题描述
给定一个整数 n
,计算所有小于等于 n
的非负整数中数字 1
出现的个数。
题目链接:数字 1 的个数
二、题目要求
样例 1
输入: n = 13
输出: 6
复制代码
样例 2
输入: n = 0
输出: 0
复制代码
考察
1.数学思想、超时优化
2.建议用时15~35min
复制代码
三、问题分析
这一题我一拿到手就感觉不对劲,明明很简单的一道题,只需要循环统计就行了,力扣居然为它加上困难的标签。
class Solution {
public:
int countDigitOne(int n) {
int i,k,ans=0;//初始化数据
for(i=1;i<=n;i++)//循环1~n
{
k=i;
while(k)//数位中是否包含1
{
if(k%10==1)
ans++;//计数
k=k/10;
}
}
return ans;//输出结果
}
};
复制代码
所以,我的代码肯定会超时。
看了题解>_<发现,这是一道规律题:
规律如下,借鉴了大佬的思路:
/**
从低往高位,计算每一位的数量:
第1位上的1的个数:1+(n-1)/10
第2位上的1的个数:(1+(n/10-1)/10)*10
第3位上的1的个数:(1+(n/100-1)/10)*100
……
第k+1位上的1的个数:(1+(n/(10^k)-1)/10)*(10^k)
如果n的第k+1位上是1,则说明可能没有填满该位,计算第k+1位的数量时还要 -10^k+1+n%(10^k),相当于独立计算
*/
复制代码
四、编码实现
class Solution {
public:
int countDigitOne(int n) {
long long k = 1,ans = 0;//初始化数据
while (n >= k){
ans += (1+(n/k-1)/10)*k;//计数
if (n/k%10 == 1) ans = ans-k+1+n%k;//当前位为1,减去数据
k *= 10;
}
return ans;//输出结果
}
};
复制代码
五、测试结果
扫描二维码关注公众号,回复:
13772186 查看本文章