算法设计之补零递归法(统计数字问题)

问题:给定一个数N求从1N的这N个数中0,1,2,3,4,5,6,7,8,910个数字出现的次数。注意,所有的数字没有前导的0。 如6要写成6,而不是 006 06这种形式

思路1:也就是最简单最容易实现的做法,但是当n很大的时候,运行时间会变得十分长

import java.util.Scanner;

public class CountPage {
	private static Scanner scanner;

	public static void main(String[] args) {
		scanner = new Scanner(System.in);
		while (scanner.hasNext()) {
			int n = scanner.nextInt();
			int j;
			int pageNum[] = new int[10];// 存放0--9的个数
			for (int i = 1; i <= n; i++) {
				int k = i;
				while (k != 0) {
					j = k % 10;
					k = k / 10;
					pageNum[j]++;
				}
			}
			 for(int i = 0;i< 10;i++)
		        {
				 	System.out.println(i+"--"+pageNum[i]);
		        }
		}
	}
}


思路2:这个思路是来自《编程之美》的

假设有一个5位数N=ABCDE,我们现在来考虑百位上出现2的次数,即:从0ABCDE的数中,有多少个数的百位上是2。分析完它,就可以用同样的方法去计算个位,十位,千位,万位等各个位上出现2的次数。 

第一种情况:当百位上的数C小于2时: 
1)当百位c0时,比如说12013012013中哪些数的百位会出现2?我们从小的数起, 200~299, 1200~1299, 2200~2299, … , 11200~11299, 也就是固定低3位为200~299,然后高位依次从011,共12个。再往下12200~12299 已经大于12013,因此不再往下。所以,当百位为0时,百位出现2的次数只由更高位决定,等于更高位数字(12)x当前位数(100)=1200个。 
2)当百位C1时,比如说12113。分析同上,并且和上面的情况一模一样。最大也只能到11200~11299,所以百位出现2的次数也是1200个。 
上面两步综合起来,可以得到以下结论: 
—>当某一位的数字小于2时,那么该位出现2的次数为:更高位数字x当前位数 

第二种情况:当百位上的数C等于2时: 
当百位C2时,比如说12213。那么,我们还是有200~299, 1200~1299, 2200~2299, … , 11200~112991200个数,他们的百位为2。但同时,还有一部分12200~12213,共14(低位数字+1)。所以,当百位数字为2时,百位出现2的次数既受高位影响也受低位影响,结论如下: 
—>当某一位的数字等于2时,那么该位出现2的次数为:更高位数字x当前位数+低位数字+1 
第三种情况:当百位上的数C大于2时: 

当百位C大于2时,比如说12313,那么固定低3位为200~299,高位依次可以从012,这一次就把12200~12299也包含了,同时也没低位什么事情。因此出现2的次数是: (更高位数字+1)x当前位数。结论如下: 
—>当某一位的数字大于2时,那么该位出现2的次数为:(更高位数字+1)x当前位数 
通过上述分析,我们可以得到以下规律: 
(1)当某一位的数字小于i时,那么该位出现i的次数为:更高位数字x当前位数 
(2)当某一位的数字等于i时,那么该位出现i的次数为:更高位数字x当前位数+低位数字+1 
(3)当某一位的数字大于i时,那么该位出现i的次数为:(更高位数字+1)x当前位数

下面使用java实现该算法:

import java.util.Scanner;

public class CountPagePro {
	private static Scanner scanner;

	public static void main(String[] args) {
		scanner = new Scanner(System.in);
		while (scanner.hasNext()) {
			int n = scanner.nextInt();
			int[] pageNum = new int[10];
			int a = 1;
			int zero = 0;
			int place = 0;// 位数
			while (n / a != 0) {
				int lowPo = a - (a / n) * n;
				int curre = (a / (n)) % 10;
				int highPo = a / (n * 10);
				place++;
				for (int i = 0; i < 10; i++) {
					if (i < curre) {
						pageNum[i] += (highPo + 1) * n;
					} else if (i == curre) {
						pageNum[i] += (highPo) * n;
						pageNum[i] += (lowPo + 1);

					} else {
						pageNum[i] += (highPo) * n;
					}
				}
				n = n * 10;
			}
			int t = 1;
			while (t <= place) {
				n = n / 10;
				zero += t * (n - 1 - n / 10 + 1);
				t++;
			}
			pageNum[0] = pageNum[0] - zero;
			for (int i : pageNum) {
				System.out.println(i + "--" + pageNum[i]);
			}
		}
	}
}



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值