您的位置:首页 > 其它

统计数字问题

2012-03-29 22:23 183 查看
【座右铭】1. 想要成为行家,就必须尝试解决大量的问题;

2. 解决大量问题并不代表能解决所有问题,而是表示解决下一个问题的几率变大了

1.一本书的页码从自然数1开始顺序编码直到自然数n。书的页码按照通常的习惯编排,每个页码都不含多余的前导0。例如第6页,而不是06页,或者006页。要求给定的页码n,统计出全部页码中出现了多少次0,1,2,...,9

第一部分:思路

1. 对于数字n=a1a2a3...ak,假设页码包含前导0,从左到右统计,统计方法如下

1.1 将a1a2a3...ak分为如下部分:

1) 从000..0(k个0)到 (a1-1)99...9之间0-9出现的次数

2) 再将a1的次数加上:a2a3...ak + 1次

3) 再递归统计n=a2a3...ak中0-9出现的次数

举例说明:n=263

1) 先统计000-199之间0-9出现的次数

2) 再将2的次数加上:63+1=64次

3) 再递归统计n=63时0-9出现的次数

1.2 统计000..0(k个0)到(a1-1)99...9之间0-9出现的次数如下:

1) 最高位0,1,2...(a1-1)都出现了10^(k-1)次

2) 在余下的k-1位中,出现了a1次从00..0(k-1个)到99..9(k-1个)。因为0-9出现的次数相等,因此0-9分别出现了 a1*(k-1)*10^(k-1)/10

举例说明:从000-199

1) 最高位0和1都出现了100次

2) 然后00-99出现了2次,因此0-9分别出现了2*2*100/10=40次

2.减去前导0,k位数中前导0的数目如下:

1个数:全是0,如00...00。推出k个前导0

9个数:非0数从倒数第1位开始,如00...0X。推出(k-1)*9个前导0

90个数:非0数从倒数2位开始,如00...0XX。推出(k-2)*90个前导0

900个数:非0数从倒数第3位开始,如00...0XXX。推出(k-3)*900个前导0

依次轮推

第二部分:Java代码,不考虑异常

/**
* 一本书的页码从自然数1开始顺序编码直到自然数n。书的页码按照通常的习惯编排,每个页码都不含多余的前导0。
* 例如第6页,而不是06页,或者006页。要求给定的页码n,统计出全部页码中出现了多少次0,1,2,...,9
* @param page
* 页码
* @return
* 一个长度为10的数组,分别表示0,1,2...9出现的次数
*/
public static int[] statistic(int page)
{
//数字不超过20位
final int integerLen = 20;
//保存数位
int[] dbit = new int[integerLen];
int len = 0;
while(page>0)
{
dbit[len++] = page%10;
page /= 10;
}
//用于步骤1.1中的第2步
int[] dnum = new int[integerLen];
dnum[0] = 0;
int base = 1, k = 1;
for(;k<len;k++)
{
dnum[k] = dbit[k-1]*base + dnum[k-1];
base *= 10;
}
k = 0;
for(;k<len;k++)
{
dnum[k]++;
}

//步骤1
int[] result = new int[10];
k = len;
base = 1;
while((--k)>0)
{
base *= 10;
}
k = len;
while((--k)>=0)
{
int curbit = dbit[k];
//步骤1.2中第1步
int j = 0;
for(;j<curbit;j++)
{
result[j] += base;
}

//步骤1.1中第2步
result[j] += dnum[k];

//步骤1.2中第2步
base /= 10;
j = 0;
int add = base*k*curbit;
for(;j<10;j++)
{
result[j] += add;
}
}

//步骤2:减去前导0
k = 1;
base = 9;
result[0] -= len;
for(;k<len;k++)
{
result[0] -= (len-k)*base;
base *= 10;
}

return result;
}

/*
* 蛮力法:用于调试
*/
static int[] statistic2(int page)
{
int[] result = new int[10];
for(int i=1;i<=page;i++)
{
int j = i;
while(j>0)
{
result[j%10]++;
j /= 10;
}
}
return result;
}


第三部分:测试用例

n=1,0到9出现的次数:0 1 0 0 0 0 0 0 0 0

n=11,0到9出现的次数:1 4 1 1 1 1 1 1 1 1

n=100,0到9出现的次数:11 21 20 20 20 20 20 20 20
20

n=2001,0到9出现的次数:494
1601 602 600 600 600 600 600 600 600

n=67321,到9出现的次数:26162
37273 37264 37184 37162 37162 34484 26484 26162 26162
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: