算法1-1: 统计数字问题

(1)、问题描述
一本书的页码从自然数1 开始顺序编码直到自然数n。书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0。例如,第6 页用数字6 表示,而不是06 或006 等。数字计数问题要求对给定书的总页码n,计算出书的全部页码中分别用到多少次数字0,1, 2,…,9。
(2)、算法设计
给定表示书的总页码的10 进制整数n (1≤n≤10 ) 。编程计算书的全部页码中分别用到多少次数字0,1,2,…,9。
 

书上要求的是文件操作:

样例输入: 
11 
样例输出: 









思路

  1. 求长度(位数)
     
  2. 拆分区间,统计除最高位数字外,其余位造成的影响

    以666为例,区间划分为000-099、100-199、... 500-599,共6个区间
    每个区间除去最高位,0-9出现次数为:(len-1)*10^(len-2)
    区间数可以归纳出来为最高位的数 hightest :n/(10^(len-1))
    所以,0-9数字的总数目为: hightest **(len-1)*10^(len-2)
     
  3. 最高位的各数字造成的影响

    0:000-099,10^2个
    1:100-199,10^2个
    ...
    6:600-666,(66+1)个
    归纳一下:最后一个数为除去最高位的数+1,其它数为10^(len-1)
     
  4. 除去最高位后余下的数,进行递归

    处理 secondPart 
    (1)若secondPart 为0,比如200,此时c[0]要加len-1也就是2,然后结束递归.
    (2)若secondPart 不为0,若len_secondPart != len-1则是类似2002的情况,中间两个0要进行处理,
         countNumber[0] += (len - len_secondPart - 1)*(secondPart + 1);

  5. 在函数外边把多加上的0减掉

    因为0开头的数字这里是不允许的,000-099这一块多算了好多0,所以要减去,即减去0开头的情况,
    有 10^0+10^1+...+10^len 个,类似于直角三角形,以3位数为例:   
    算法1-1: 统计数字问题_第1张图片

 

 

实现

#include 
#include 
#include 
#include 

using namespace std;

int countNumber[10] = { 0 };	//记录每个数字出现位数

void counter(int n)
{
	/*
	while (n % 10 != 0)	//求位数len,实际上用的是len-1,例如666拆分:00-99,100-199,...
	{
	len++;
	tempn /= 10;
	}
	int i = 0;
	for (i = 0; i < len - 1; i++)	//求最高位是几
	{
	highest /= 10;
	}
	*/

	//求位数len
	int len = log10(n) + 1;
	//求最高位是几
	int highest = n / ((int)round(pow(10.0, len - 1)));

	//拆分区间,计算除最高位外造成的影响
	for (int i = 0; i < 10; i++)
	{
		countNumber[i] += highest*(len - 1)*(int)round(pow(10.0, len - 2));
	}

	//最高位造成的影响
	for (int i = 0; i < highest; i++)
	{
		countNumber[i] += (int)round(pow(10.0, len - 1));
	}
	int temp = (int)round(pow(10.0, len - 1));
	int secondPart = n%temp;
	if (secondPart == 0)
	{
		countNumber[highest] += 1;
		countNumber[0] += len - 1;
		return;
	}
	else
	{
		int len_secondPart = log10(secondPart) + 1;
		if (len_secondPart != len - 1)	//处理201,2001...中间有0的情况,要把0出现的次数加上,因为递归不会额外计算
		{
			countNumber[0] += (len - len_secondPart - 1)*(secondPart + 1);
			//先算出来有几个0,再对0进行统计
		}
		countNumber[highest] += secondPart + 1;		//最高位最大数字的处理

		//递归计算除去最高位后剩下的数
		return counter(secondPart);
	}
}


int main()
{
	int n;
	ifstream input;
	input.open("G://a.txt");
	ofstream output;
	output.open("G://b.txt");
	input >> n;

	counter(n);
	int len = log10(n) + 1;
	for (int i = 0; i < len; i++)
	{
		countNumber[0] -= (int)round(pow(10.0, i));	//因为多加了,所以要减掉
	}

	//输出
	for (int i = 0; i < 10; i++)
	{
		output << countNumber[i] << endl;
	}

	output.close();
	input.close();
	return 0;
}

 

我的错误想法

死胡同:不把一个数字拆分,而去直接利用公式进行递归,但是这个公式只适用于全是9的情况,公式如下:

                  

 

你可能感兴趣的:(算法分析与设计(课程))