牛牛新买了一本算法书,算法书一共有n页,页码从1到n。牛牛于是想了一个算法题目:在这本算法书页码中0~9每个数字分别出现了多少次?
统计在1-n个数字中,0、1、2、3……9各出现了多少次
首先简化,判断1-n个数字中,i出现的次数,0<=i <=9。
//计算1-n的整数中,i出现的次数
int nCount(int n, int i)
{
int num = 0;
for ( int temp =1; temp <=n; temp++) {
int tt = temp;
while (tt !=0) {
if (tt % 10 == i) {
num++;
}
tt/=10;
if (tt == 0) {
continue;
}
}
}
return num;
}
int main(int argc, const char * argv[]) {
// insert code here...
int n;
while (cin >>n) {
for (int i=0; i<9; i++) {
cout << nCount(n, i) << " ";
}
cout << nCount(n, 9);
}
return 0;
}
以上方法时间复杂度非常大,无法满足要求。
根据编程之美所说,对于一个n位数m,要统计1-m中数字1出现的次数,就依次判断n位中每一位是1分别有多少情况,加起来就是总的次数。
比如数123,是个3位数。为别统计个位为1,十位为1,百位为1的数各有多少,加起来就是1-123中出现1的次数。
每一位为1的数量,与他的高位、低位有关。
int cal(int page, int data)
{
int num =0;
int temp =1;
int low = 0; //记录当前位的低位
int orig = page;
while (page != 0) {
if (page % 10 > data)
{
num += (page/10+1)*temp;
}
else if (page % 10 < data)
{
num += (page/10)*temp;
}
else
{
num += (page/10)*temp + (low+1);
}
temp *= 10;
low = orig - (orig/temp)*temp;
page /= 10;
}
return num;
}
以上只使用于统计1-9出现的次数,因为没有比0还小的数,所以上述方法的第一种情况不适用于统计0出现的
int cal0(int page)
{
int num =0;
int temp =1;
int low = 0;
int orig = page;
while (page != 0) {
if (page % 10 == 0) {
num += (page/10 -1)*temp + (low +1);
}
else
{
num += (page /10)*temp;
}
temp *= 10;
low = orig - (orig/temp)*temp;
page /= 10;
}
return num;
}
所以综上int main(int argc, const char * argv[]) {
// insert code here...
int n;
while (cin >>n) {
cout << cal0(n);
for (int i=1; i <10; i++) {
cout << " " << cal(n, i);
}
}
return 0;
}
顺利通过!