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

题目描述

原题链接
AcWing 338.计数问题 (类似整数中1出现的次数 数位统计DP C++)_第1张图片

算法

(数位统计) O ( m l o g n ) O(mlogn) O(mlogn)

相似题目:剑指offer | 整数中1出现的次数(从1到n整数中1出现的次数)(数位统计 logN复杂度 C++)
(1)求 a a a b b b 之间的 k k k 的个数(k = [0,…9]),我们只要统计从 1 1 1 a − 1 a - 1 a1 k k k 的个数,从 1 1 1 b b b k k k 的个数,然后让他们相减即可
(2) 而统计从 1 1 1 n n n k k k 的个数的方法可以看【剑指offer | 整数中1出现的次数】传送门 这个题, 注意 k = 0 k = 0 k=0 时要删去一部分数
(3)注意 a a a 大于 b b b 时要交换它们

图解:以统计从 1 1 1 n n n 1 1 1 的个数为例

AcWing 338.计数问题 (类似整数中1出现的次数 数位统计DP C++)_第2张图片

时间复杂度是 O ( m l o g n ) O(mlogn) O(mlogn):m为询问的次数,空间复杂度是 O ( l o g n ) O(logn) O(logn)

C++代码

#include 
#include 

using namespace std;

// Get the number of k from 1 to n
int kNumbers(int n, int k) {
    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 (k == 0) res -= t; // 0 is special
        if (answer[i] == k) res += right + 1;
        if (answer[i] > k) res += t;
    }
    return res;
}

int main() {
    int a, b;
    int A[10], B[10]; // A[i] means the number of i from 1 to a 
    
    while(cin >> a >> b && a != 0 && b != 0) {
        if (a > b) swap(a, b);
        
        for (int i = 0; i < 10; i ++) {
            A[i] = kNumbers(a - 1, i);
            B[i] = kNumbers(b, i);
            cout << B[i] - A[i] << " ";
        }
        cout << endl;
    }


    return 0;
}


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

你可能感兴趣的:(LeetCode)