剑指 Offer 43. 1~n 整数中 1 出现的次数 C++ 困难

10 篇文章 0 订阅

1 常规思路 暴力求解——超时

class Solution {
public:
    int countDigitOne(int n) {
        int res = 0;
        for(int i = 1; i <= n; i++){
            res += IncludeYi(i) ;
        }
        return res;
    }
private:
    int IncludeYi(int n){
        int res = 0;
        while(n > 0){
            int m = n % 10;
            n = n / 10;
            if(m == 1) res++;
        }
        return res;
    }
};

2  个位遍历到最高位依次求解

解析

需要通过找规律来分析。
假设我们对5014这个数字求解。
     (1)个位上1出现的个数:记高位为high=501,当前位为cur=4。
那么高位从0~500变化的过程中,每一个变化中1只出现1次,即(高位1)这样的数字;
高位是501时,因为当前位是4,所以1只能出现一次,即5011。
所以总共出现的次数为high*1+1=502。
     (2)十位1出现的个数:记高位high=50,当前位为cur=1,低位为low=4。
那么高位从0~ 49变化的过程中,每一个变化中1出现10次,即(高位10)~(高位19)这样的数字;
高位为50的时候,因为当前位是1,所以我们要看低位来决定出现的次数,因为低位为4,所以此时出现5次,即5010~5014这样的数字。
所以总共出现的次数为high*10+4=504。
     (3)百位1出现的个数:记高位high=5,当前位cur=0,低位为low=14。
那么高位从0~ 4的过程中,每一个变化1出现100次,即(高位100)~(高位199)这样的数字;
高位为5的时候,因为当前位为0,所以不存在出现1的可能性。
所以总共出现的次数为high*100+0=500。
     (4)千位1出现的次数:记高位high=0,当前位cur=5,低位low=014。
那么因为没有高位所以直接看当前位,因为当前位为5,所以1出现的次数为1000,即1000~1999这样的数字。
所以总共出现的次数为high*1000+1000=1000。
     综上,最终的结果将每个位置出现1的次数累加即可。

结论


我们假设高位为high,当前位为cur,低位为low,i代表着需要统计的位置数(1对应个位,10对应十位,100对应百位),则对每一位的个数count有:
cur=0,count = high*i;
cur=1,count=high*i+low+1;
cur>1,count=high*i+i
最终累加所有位置上的个数即最终答案。

class Solution {
public:
    int countDigitOne(int n) {
       int count = 0;
       long i = 1;//指向遍历的位数,如i=1即个位,i=10即十位,...,因为n可以有31位,所以10^31用long存储
       while(n/i!=0){
           //n/i控制遍历的次数,将所有的位数都遍历完毕
            long high = n/(10*i);//将当前位之前的所有高位都存在high中
            long cur = (n/i)%10;//将当前位记录在cur中,即我们每次都需要统计当前位上1出现的次数
            long low = n-(n/i)*i;
            if(cur == 0){
                count += high * i;
            } else if(cur == 1){
                count += high * i + low + 1;
            } else {
                count += high * i + i;
            }
            i = i * 10;//准备遍历下一位
       }
       return count;
    }
};

时间复杂度O(logn) : 循环内的计算操作使用O(1) 时间;循环次数为数字 n 的位数,即 log 10(n),因此循环使用O(logn) 时间。
空间复杂度O(1) : 几个变量使用常数大小的额外空间。

参考

https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/solution/mian-shi-ti-43-1n-zheng-shu-zhong-1-chu-xian-de-2/

https://leetcode-cn.com/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/solution/c-cong-ge-wei-bian-li-dao-zui-gao-wei-yi-ci-qiu-ji/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值