算法设计与分析-统计数字问题(暴力、分治递归)(通俗易懂,附源码和图解,含时间复杂度分析)(c++)

这篇博客介绍了两种方法来计算一本书页码中数字0到9的出现次数。方法一是暴力遍历,从1到n依次拆解页码并统计;方法二是递归计算,利用数学规律减少计算量。复杂度分析显示递归方法的时间复杂度更低,为O(nlogn),而暴力方法的时间复杂度为O(n^2)。

1-1统计数字问题

(一)题目

问题描述

一本书的页码从自然数 1 开始顺序编码到自然数nnn。书的页码按照通 常的习惯编排,每个页码都不含多余的前导 0。例如,第 6 页用数字 6 表示而不 是 06 或 006 等。数字计数问题要求对给定书的总页码nnn,计算书的全部页码分别 用到多少次数字 0,1,2,……,9。

算法设计

给定表示书的总页码的十进制整数n(1≤n≤109)n(1\leq n\leq10^{9})n(1n109),计算书的全部页 码中分别用到多少次数字 0,1,2,……,9。 数据输入:输入数据由文件名为input.txt的文本文件提供。每个文件只有1行, 给出表示书的总页码的整数nnn

结果输出

将计算结果输出到文件 output.txt。输出文件共 10 行,在第 k(k=1,2,……,10)k(k=1,2,……,10)k(k=1,2,,10)行输出页码中用到数字$ k-1$ 的次数。

(二)解答

方法1.暴力
算法思路

从 0 到nnn依次遍历每一页的页码,把页码从低位到高位用循环依次拆开,记录每个数字的出现次数。

举例

在这里插入图片描述

源代码
#include<iostream>
#include<cstdio>
#include<fstream>

using namespace std;

//读取
int read(); 
//写入
void write(int a[]);
//计算总页码0-9出现的次数
void solution(int n, int a[]);

int main()
{
   
   
    int a[10] = {
   
   0};
    //从输入文件获取总页数n
    int n = read();
    //计算0-9出现的次数
    solution(n, a);
    //将0-9的出现次数写入输出文件
    write(a);
    return 0;
}

int read()
{
   
   
    ifstream ifs;
    //打开输入文件
    ifs.open("G:\\algorithm\\data\\1_1_input.txt", ios::in);
    //读取数据
    int n;
    ifs>>n;
    //关闭输入文件
    ifs.close();
    //返回总页数n;
    return n;
}

void write(int a[])
{
   
   
    ofstream ofs;
    //创建输出文件
    ofs.open("G:\\algorithm\\data\\1_1_1out.txt", ios::out);
    //写入数据
    for (int i = 0; i < 10; ++i)
    {
   
   
        ofs<<a[i]<<endl;
    }
    //关闭输出文件
    ofs.close();
}

void solution(int n, int a[])
{
   
   
    //依次遍历每一页的页码i
    for (int i = 1; i <= n; ++i)
    {
   
   
        //用t暂时存储页码i
        int t = i;
        //从右往左依次记录t每一位上的数字的出现次数,直到t=0
        while (t)
        {
   
   
            a[t % 10]++;
            t /= 10;
        }
    }
}
方法2.递归
算法思路

对于从 nnn 个 0 到 nnn 个 9 的数,它们中 0-9 出现的次数相同,记为f(n)f(n)f(n)

在这里插入图片描述

通过观察可以得出递归式:
f(n)={ 1,    n=110f(n−1)+10n−1,n>1 f(n)=\begin{cases} 1,\;\;\qquad \qquad \qquad \quad \qquad n=1\\ 10f(n-1)+10^{n-1},\qquad n>1\\ \end{cases} f

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值