[编程题]页码统计

题目

牛客网 https://www.nowcoder.com/questionTerminal/3a003cb6a3174ef9835fa603e01d8b52

牛客网原题:
牛牛新买了一本算法书,算法书一共有n页,页码从1到n。牛牛于是想了一个算法题目:在这本算法书页码中0~9每个数字分别出现了多少次?

思路

按位数某个数字出现过多少次。也就是说,固定某一位上的某个数,看看此时有几种情况。

举个栗子:
对统计1~785012中5出现的个数
我们先考虑5在低位第三位出现的次数,我们就将第三位固定为5:XXX5XX。
此时,问题就转化为,“X”处一共有多少种组合方式。
高位的3位可以从000到785之间,低位的2位可以从00到99之间。
但是,当高3位为785时,7855XX无论如何都超过了785012,因此,高三位可以选择的只有000~784(共785个数字),高三位和低二位一共有785*100种组合方式。

我们再考虑5在低位第四位出现的次数,我们就将第四位固定为5:XX5XXX。
与前面相同,高位的二位可以从00到78之间,低位的三位可以从000到999之间。
当高位是00到77时,与前面一种情况是相同的,一共可以组合出78*1000种情况。
当高位是78时,785XXX就有超过785012的可能了,后三位的选择局限在000到012之间,共13中情况。
两者结合就是:78*1000+13

最后考虑5在低位第5位出现的次数,我们就将第五位固定为5:X5XXXX。
与前面相同,最高位可以从0取到7,低四位可以从0000取到9999.
当最高位为0到6时,与第一种情况相同,一共可以组合出7*10000中情况。
当高位是7时,与前面的情况不同的是,75XXXX是不会越界的,后四位可以从0000取到9999,所以可以组合出10000中情况。
两者结合就是:7*10000+10000

但是,当统计0的个数时,情况又有所不同。还用785012讨论,如果我们要统计低位低2位出现0的次数,按照前面的方法,我们可能把00000X讨论进来,认为这也是第二位出现0的情况,但是这个数只能表示为X,它的第二位根本不存在。
因此,针对0这种情况,我们需要单独讨论,只需要分成两类,不可能存在当前位小于0的情况,不过每次高位的取值要把全0的情况剔除。

代码

我的代码如下

#include <iostream>
using namespace std;

//count the bit of N, and the low_n/high_n at lowest bit/highest bit
int countBit(int n, int *low_n, int *high_n)
{
	int t = n;
	int res = 0;
	int high;
	*low_n = t % 10;
	while (t > 0)
	{
		res++;
		high = t % 10;
		t = t / 10;
	}
	*high_n = high;
	return res;
}

int pow(int n, int x)
{
	int t = 1;
	for (int i = 0; i < x; i++)
		t *= n;
	return t;
}

int main(int argc, char** argv)
{
	int n;
	int i, j, k, t;
	int low, high, len;	//low: 0th number; high: len-th number; len: lenghth of n;
	int lown, highn, curn;	//highn: number before current bit, lown: after curent bit; curn: current bit;
	int result[10];
	
	cin >> n;
	len = countBit(n, &low, &high);

	for (i = 0; i < 10; i++)	result[i] = 0; 
	for (i = 0; i < len; i++)
	{
		t = pow(10, i);
		highn = n / (t * 10);	lown = n%t;	curn = (n/t) % 10;
		for (j = 0; j < 10; j++)
		{
			if (j == 0)
			{
				if (i == len - 1)
					continue;
				if (curn == 0)
					result[j] += (highn - 1)*t + (lown + 1);
				else
					result[j] += highn * t;
			}
			else if (j == curn)
				result[j] += highn * t + (lown + 1);				
			else if (j>curn)
				result[j] += highn * t;
			else //j<curn && j!=0
				result[j] += (highn+1) * t;
		}
	}
	//output
	cout << result[0];
	for (i = 1; i < 10; i++)
		cout << " " << result[i];
	return 0;
}

 PS,自己写pow函数的原因 - 公司的算法考试不允许使用stdlib和stl,所以习惯自己写。

这是我的第一个newcoder题。