剑指offer | 整数中1出现的次数(从1到n整数中1出现的次数)(数位统计 logN复杂度 C++)

题目描述

原题链接

求出1 ~ 13的整数中1出现的次数,并算出100 ~ 1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

算法

(数位计算) O ( l o g n ) O(logn)
(1)计算每一位上的1出现的个数(从1到n)
(2) 总共循环 l o g n logn 次,即n的位数

算法思路图解

时间复杂度是 O ( l o g n ) O(logn) :下面代码时间复杂度是 O ( l o g 2 n ) O(log^2n) ,但其中一个是不会大于32的;另外我们还可以预处理left和right

空间复杂度是 O ( l o g n ) O(logn) :需要answer数组存数位信息

进阶题目:AcWing 338.计数问题 (类似整数中1出现的次数 数位统计DP C++)

C++代码1

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n) {
        if (!n) return 0;
        // n = 123 answer = [3, 2, 1]
        vector<int> answer; 
        while(n) answer.push_back(n % 10), n /= 10;
        
        int res = 0;
        for (int i = answer.size() - 1; i >= 0; i --) {
            int left = 0, right = 0, t = 1;
            for (int j = answer.size() - 1; j > i; j --) left = left * 10 + answer[j];
            for (int j = i - 1; j >= 0; j --) right = right * 10 + answer[j], t *= 10;
            
            res += left * t;
            if (answer[i] == 1) res += right + 1;
            if (answer[i] > 1) res += t;
        }
        
        return res;
    }
};

C++ 代码2 暴力做法

class Solution {
public:
    int countOne(int n) {
        int ans = 0;
        while(n) {
            if (n % 10 == 1) ans ++;
            n /= 10;
        }
        
        return ans;
    }
    int NumberOf1Between1AndN_Solution(int n)
    {
        int res = 0;
        for (int i = 1; i <= n; i ++) {
            res += countOne(i);
        }
        return res;
    }
};

写在最后:我的博客主要是对计算机领域所学知识的总结、回顾和思考,把每篇博客写得通俗易懂是我的目标,分享技术和知识是一种快乐 ,非常欢迎大家和我一起交流学习,有任何问题都可以在评论区留言,也期待与您的深入交流(^∀^●)

发布了270 篇原创文章 · 获赞 111 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/qq_43827595/article/details/104484543
今日推荐