输入m∈[1,9],输入任意正整数n,求n里出现了多少次数字m

第一种是线性实现,轮询每个数字,到百万量级时就不行了

//
//    
//
//    
int count_nums(int m, int n)
{
    int count = 0;
    char n_str = m + '0';
    //  n里多少个数字有m
    for(int i=1; i<n; ++i){
        for(const char &ch : to_string(i))
            if(ch == n_str){
                count += 1;
                break;
            }
    }

    return count;
}

第二种是先构造一个每位有多少相同数字的表,然后查表实现,由牛客网@言1997 同学提供
帖子地址:https://www.nowcoder.com/discuss/630291?source_id=profile_create_nctrack&channel=-1

//
//    输入m∈[1,9],输入任意正整数n,求n里出现了多少次数字m
//
//    第一种是线性实现,鄙视
int count_nums2(int m, int n)
{
    int n1 = n / 10, k = 10, idx;
    vector<int> count = { 0,1 }, nums = { n % 10 };
    while (n1 > 0) {
        count.push_back(count.back() * 9 + k);
        nums.push_back(n1 % 10);
        k *= 10;
        n1 /= 10;
    }
//    for(int i:count) cout<<i<<' ';
//    cout<<endl;
//    for(int i:nums) cout<<i<<' ';
//    cout<<endl;
    int ans = 0;
    for (int i = nums.size() - 1; i > -1; --i) {
        k /= 10;
        //cout<<k<<endl;
        if (nums[i] <= m) {
            ans += count[i] * nums[i];
            if (nums[i] == m) {
                ans += n % k;
                break;
            }
        }
        else {
            ans += count[i] * (nums[i] - 1) + k;
        }
    }
    return ans;
}

第三种是我自己实现的查表法,毕竟懂原理是一方面,会敲出来是另一方面

vector<int> create_table(int number, bool print=false)
{
    // 构造表
    vector<int> unit_count = {0, 1};
    for(int unit=100; unit < number; unit*=10) {
        int count = 9 * unit_count[unit_count.size()-1] + unit / 10;
        unit_count.push_back(count);
    }

    // 输出构造后的表结构
    cout << "{ ";
    if(print)
        for(const int& val : unit_count)
            cout << val << ' ';
    cout << " }" << endl;

    //
    return unit_count;
}


int count_nums3(int m, int n, const vector<int>& table = vector<int>())
{
    int ret = 0;
    vector<int> tb = table.empty() ? create_table(n) : table;

    //  将目标拆分为两部分
    int tail = 0;
    auto str = to_string(n);
    auto idx = str.find(m+'0');
    if(idx != string::npos && idx != str.size()-1) {
        n = stoi(str.substr(0, idx+1));
        auto tmp = str.substr(idx+1, str.size()-idx);
        tail = stoi(tmp);
        n *= pow(10, tmp.size());
        str = to_string(n);
    }

    //
    int unit = 1;
    for(int i=0, len=str.size();
        i < len;
        ++i, unit*=10)
    {
        int bit = str[len - i - 1] - '0';   //  获取该十进制bit上的元素
        auto tmp = (bit - (bit > m)) * tb[i] + (bit > m) * unit;
        ret += tmp;
    }

    //
    cout << ret << "   " << tail << "  " << n << endl;
    ret += tail;
    return ret;
}

这里是测试用的主函数

int main() {
    //  输入m∈[1,9],输入任意正整数n,求n里出现了多少次数字m
    int m, n;
    m = 2;
    n = 316541656;

    //
    auto table = create_table(n, true);
    auto res = count_nums3(m, n, table);
    cout << "count_nums3:\t" <<  res << endl;
    cout << "count_nums2:\t" <<  count_nums2(m, n) << endl;
    cout << "count_nums:\t" <<   count_nums(m, n) << endl;
}