算法题每日一练---第72天:数字 1 的个数

一起养成写作习惯!这是我参与「掘金日新计划 · 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.png

17.png

看了题解>_<发现,这是一道规律题:

2.png

规律如下,借鉴了大佬的思路:

/**
从低往高位,计算每一位的数量:
第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;//输出结果
    }
};
复制代码

五、测试结果

4.png

扫描二维码关注公众号,回复: 13772186 查看本文章

3.png

猜你喜欢

转载自juejin.im/post/7083646563754442783
今日推荐