统计页码数字问题
2013-06-10 12:29
246 查看
统计数字问题
问题描述:
一本书的页码从自然数1 开始顺序编码直到自然数n。书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0。例如,第6
页用数字6 表示,而不是06 或006 等。数
字计数问题要求对给定书的总页码n,计算出书的全部页码中分别用到多少次数字0,1,2,…,9。
编程任务:
给定表示书的总页码的10 进制整数n (1≤n≤109)
。编程计算书的全部页码中分别用到多少次数字0,1,2,…,9。
数据输入:
输入数据由文件名为input.txt的文本文件提供。每个文件只有1 行,给出表示书的总页码的整数n。
结果输出:
程序运行结束时,将计算结果输出到文件output.txt中。输出文件共有10行,在第k行
输出页码中用到数字k-1 的次数,k=1,2,…,10。
输入文件示例 输出文件示例
input.txt
11
output.txt
1
4
1
1
1
1
1
1
1
1
解题思路1:根据输入的数字Num,从1到Num 一 一统计每个数字出现的次数。
算法时间复杂度:O(n*log10(n))
算法:
for(i = 1; i <= n; i++)
{
t = i;
while(t) {
count[t%10]++;
//count数组是每个数字出现次数的计数器
t/=10;
}
}
![](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
f(n)=10*f(n-1)+10^(n-1)
f(n-1)=10*f(n-2)+10^(n-2)
f(n-2)=10*f(n-3)+10^(n-3)
.
.
.
f(2)=10f(1)+10^1
可见:f(n)=10^(n-1)+(n-1)*10^(n-1)
即:f(n)=n*10^(n-1),利用此公式计算每个数字的出现次数,计算0的出现次数时,最后减去多余的前导0的出现次数即可。
举例(取区间法):
比如计算32871,从高位向低位看,可以看到该数包含3个0000~9999的区间(0~9999,10000~19999,20000~29999),即每个数字出现的次数为3f(4),其中多余的前导0出现在0000~9999区间中,经观察可知多了10^3+10^2+10^1+1个0。(0000-0999,10^3个0;000-099,10^2个0;00-09,10^1个0;开始的0,10^0个0)
其中,最高位上1,2共出现10^4次。接着计算30000~32871,此处最高位的3共出现2872次。于是,着眼点就落在0000~2871中各数字的出现次数上,此时依照上面的取区间法,一次一次去掉最高位,直到剩下个位时为止,这里不会有多余的前导0(你懂的)。
算法时间复杂度:log10(n)
inline int Process(int n)
//f(n)=n*10^(n-1)原著公式
{
return n*pow(10,n-1);
}
void Dispose(int a[],int n,int &c0)//页码处理过程
{
int t=log10(n),temp=n;//假设输入数字为m位,t表示m-1
while(t)
{
temp/=pow(10,t);//temp为最高位数字
if(temp!=0)
{
n-=temp*pow(10,t);//去除最高位数字
for(int i=0;i<=9;i++)
a[i]+=temp*Process(t);//每位数字加上m*f(m-1),即一个高位乘以低m-1位的区间
}
a[temp--]+=n+1;//高位数字因低m-1位数字的出现次数
while(temp>=0)a[temp--]+=pow(10,t);//同上
c0+=pow(10,t);//需要去除多余0的个数
//while与c0这两步可改为while(temp>0)a[temp--]+=pow(10,t);这样做在主函数中只需减去1个多余前导0
if(n<<span
style="color: rgb(0, 0, 255);
">10&&t==1)
{
for(int i=0;i<=n;i++)
a[i]++;
n=0;
}
temp=n;
t--;
}
}
源代码:
#include
#include
#include
#include
#include
using namespace std;
inline int Process(int n)//f(n)=n*10^(n-1)原著公式
{
return n*pow(10,n-1);
}
void Dispose(int a[],int n,int &c0)//页码处理过程
{
int t=log10(n),temp=n;//假设输入数字为m位,t表示m-1
while(t)
{
temp/=pow(10,t);//temp为最高位数字
if(temp!=0)
{
n-=temp*pow(10,t);//去除最高位数字
for(int i=0;i<=9;i++)
a[i]+=temp*Process(t);//每位数字加上m*f(m-1),即一个高位乘以低m-1位的区间
}
a[temp--]+=n+1;//高位数字因低m-1位数字的出现次数
while(temp>=0)a[temp--]+=pow(10,t);//同上
c0+=pow(10,t);//需要去除多余0的个数
//while与c0这两步可改为while(temp>0)a[temp--]+=pow(10,t);这样做在主函数中只需减去1个多余前导0
if(n<<span
style="color: rgb(0, 0, 255);
">10&&t==1)
{
for(int i=0;i<=n;i++)
a[i]++;
n=0;
}
temp=n;
t--;
}
}
void write()
{
fstream t;
t.open("F:\\Input.txt",ios::out);
if(!t)
{
cout<<"Can't open
Input.txt"<<endl;
return;
}
srand((unsigned)time(NULL));
for(int i=0;i<<span
style="color: rgb(0, 0, 255); ">20;i++)
t<<rand()%10000<<endl;
t.close();
}
void main()
{
int n,a[10]={0},c0=0;//c0是多余的0的总数
fstream f,fo;
write();
fo.open("F:\\Output.txt",ios::out);
if(!fo)
{
cout<<"Can't open
Output.txt"<<endl;
return;
}
f.open("F:\\Input.txt",ios::in);
if(!f)
{
cout<<"Can't open
Input.txt"<<endl;
return;
}
while(!(f>>n).eof())
{
if(n<<span
style="color: rgb(0, 0, 255); ">10)
{
for(int i=1;i<=n;i++)
a[i]++;
for(int i=0;i<=n;i++)
cout<<a[i]<<endl;
return;
}
Dispose(a,n,c0);
a[0]-=c0+1;//减去多余的0
for(int i=0;i<=9;i++)
cout<<a[i]<<"
";
cout<<endl;
for(int i=0;i<<span
style="color: rgb(0, 0, 255); ">10;i++)
fo<<a[i]<<"
";
fo<<endl;
for(int i=0;i<<span
style="color: rgb(0, 0, 255); ">10;i++)
a[i]=0;
c0=0;
}
f.close();
fo.close();
}
源码在Vs2012中编写,在其他编译其中可能会存在兼容问题(某些代码格式的不支持),请自行调试(很简单)。
运行前须在F盘根目录下分别建立“Input.txt”与“Output.txt”两个文本文件,也可以将文件处理部分注释掉运行。
算法1,2可自行设计CLOCK函数测试时间,算法2会明显快于算法1。
问题描述:
一本书的页码从自然数1 开始顺序编码直到自然数n。书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0。例如,第6
页用数字6 表示,而不是06 或006 等。数
字计数问题要求对给定书的总页码n,计算出书的全部页码中分别用到多少次数字0,1,2,…,9。
编程任务:
给定表示书的总页码的10 进制整数n (1≤n≤109)
。编程计算书的全部页码中分别用到多少次数字0,1,2,…,9。
数据输入:
输入数据由文件名为input.txt的文本文件提供。每个文件只有1 行,给出表示书的总页码的整数n。
结果输出:
程序运行结束时,将计算结果输出到文件output.txt中。输出文件共有10行,在第k行
输出页码中用到数字k-1 的次数,k=1,2,…,10。
输入文件示例 输出文件示例
input.txt
11
output.txt
1
4
1
1
1
1
1
1
1
1
解题思路1:根据输入的数字Num,从1到Num 一 一统计每个数字出现的次数。
算法时间复杂度:O(n*log10(n))
算法:
for(i = 1; i <= n; i++)
{
t = i;
while(t) {
count[t%10]++;
//count数组是每个数字出现次数的计数器
t/=10;
}
}
![](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
f(n)=10*f(n-1)+10^(n-1)
f(n-1)=10*f(n-2)+10^(n-2)
f(n-2)=10*f(n-3)+10^(n-3)
.
.
.
f(2)=10f(1)+10^1
可见:f(n)=10^(n-1)+(n-1)*10^(n-1)
即:f(n)=n*10^(n-1),利用此公式计算每个数字的出现次数,计算0的出现次数时,最后减去多余的前导0的出现次数即可。
举例(取区间法):
比如计算32871,从高位向低位看,可以看到该数包含3个0000~9999的区间(0~9999,10000~19999,20000~29999),即每个数字出现的次数为3f(4),其中多余的前导0出现在0000~9999区间中,经观察可知多了10^3+10^2+10^1+1个0。(0000-0999,10^3个0;000-099,10^2个0;00-09,10^1个0;开始的0,10^0个0)
其中,最高位上1,2共出现10^4次。接着计算30000~32871,此处最高位的3共出现2872次。于是,着眼点就落在0000~2871中各数字的出现次数上,此时依照上面的取区间法,一次一次去掉最高位,直到剩下个位时为止,这里不会有多余的前导0(你懂的)。
算法时间复杂度:log10(n)
inline int Process(int n)
//f(n)=n*10^(n-1)原著公式
{
return n*pow(10,n-1);
}
void Dispose(int a[],int n,int &c0)//页码处理过程
{
int t=log10(n),temp=n;//假设输入数字为m位,t表示m-1
while(t)
{
temp/=pow(10,t);//temp为最高位数字
if(temp!=0)
{
n-=temp*pow(10,t);//去除最高位数字
for(int i=0;i<=9;i++)
a[i]+=temp*Process(t);//每位数字加上m*f(m-1),即一个高位乘以低m-1位的区间
}
a[temp--]+=n+1;//高位数字因低m-1位数字的出现次数
while(temp>=0)a[temp--]+=pow(10,t);//同上
c0+=pow(10,t);//需要去除多余0的个数
//while与c0这两步可改为while(temp>0)a[temp--]+=pow(10,t);这样做在主函数中只需减去1个多余前导0
if(n<<span
style="color: rgb(0, 0, 255);
">10&&t==1)
{
for(int i=0;i<=n;i++)
a[i]++;
n=0;
}
temp=n;
t--;
}
}
源代码:
#include
#include
#include
#include
#include
using namespace std;
inline int Process(int n)//f(n)=n*10^(n-1)原著公式
{
return n*pow(10,n-1);
}
void Dispose(int a[],int n,int &c0)//页码处理过程
{
int t=log10(n),temp=n;//假设输入数字为m位,t表示m-1
while(t)
{
temp/=pow(10,t);//temp为最高位数字
if(temp!=0)
{
n-=temp*pow(10,t);//去除最高位数字
for(int i=0;i<=9;i++)
a[i]+=temp*Process(t);//每位数字加上m*f(m-1),即一个高位乘以低m-1位的区间
}
a[temp--]+=n+1;//高位数字因低m-1位数字的出现次数
while(temp>=0)a[temp--]+=pow(10,t);//同上
c0+=pow(10,t);//需要去除多余0的个数
//while与c0这两步可改为while(temp>0)a[temp--]+=pow(10,t);这样做在主函数中只需减去1个多余前导0
if(n<<span
style="color: rgb(0, 0, 255);
">10&&t==1)
{
for(int i=0;i<=n;i++)
a[i]++;
n=0;
}
temp=n;
t--;
}
}
void write()
{
fstream t;
t.open("F:\\Input.txt",ios::out);
if(!t)
{
cout<<"Can't open
Input.txt"<<endl;
return;
}
srand((unsigned)time(NULL));
for(int i=0;i<<span
style="color: rgb(0, 0, 255); ">20;i++)
t<<rand()%10000<<endl;
t.close();
}
void main()
{
int n,a[10]={0},c0=0;//c0是多余的0的总数
fstream f,fo;
write();
fo.open("F:\\Output.txt",ios::out);
if(!fo)
{
cout<<"Can't open
Output.txt"<<endl;
return;
}
f.open("F:\\Input.txt",ios::in);
if(!f)
{
cout<<"Can't open
Input.txt"<<endl;
return;
}
while(!(f>>n).eof())
{
if(n<<span
style="color: rgb(0, 0, 255); ">10)
{
for(int i=1;i<=n;i++)
a[i]++;
for(int i=0;i<=n;i++)
cout<<a[i]<<endl;
return;
}
Dispose(a,n,c0);
a[0]-=c0+1;//减去多余的0
for(int i=0;i<=9;i++)
cout<<a[i]<<"
";
cout<<endl;
for(int i=0;i<<span
style="color: rgb(0, 0, 255); ">10;i++)
fo<<a[i]<<"
";
fo<<endl;
for(int i=0;i<<span
style="color: rgb(0, 0, 255); ">10;i++)
a[i]=0;
c0=0;
}
f.close();
fo.close();
}
源码在Vs2012中编写,在其他编译其中可能会存在兼容问题(某些代码格式的不支持),请自行调试(很简单)。
运行前须在F盘根目录下分别建立“Input.txt”与“Output.txt”两个文本文件,也可以将文件处理部分注释掉运行。
算法1,2可自行设计CLOCK函数测试时间,算法2会明显快于算法1。
相关文章推荐
- 统计数字问题。给定一本书,其中包含n页,计算出书的全部页码中用到了多少个数字0…9。
- python应用_统计数字问题,计算书的页码
- python计算书页码的统计数字问题实例
- 统计数字问题。给定一本书,其中包含n页,计算出书的全部页码中用到了多少个数字0…9。
- 统计数字问题。给定一本书,其中包含n页,计算出书的全部页码中用到了多少个数字0…9。
- 统计数字问题
- 统计数字问题
- 统计数字问题
- 统计页码中数字出现的次数
- 计算页码,统计0到9数字出现的次数
- noj1201 统计数字问题
- 统计数字问题[算法设计与分析]
- 1-1 统计数字问题
- 统计数字问题
- 统计数字问题
- C++实现页码数字统计
- 算法分析与设计之统计数字问题
- 数字统计问题
- 统计数字问题