页码数字计算

/**
 * 问题:一本书的页码是从自然数1开始编码到n的。每个页码没有前导0,即第6页编码为6,而不是<br>
 * 06,或者006.数字计数问题的要求是对给定书的总页码n,计算出书的全部页码中分别用刀的多少次<br>
 * 0,1,……9.。1<=n<=10^9。
 * 思路:对于一个数字t(0<=t<=9),分别考虑个位、十位……到n的最高位,这些位为t的数的个数,再分<br>
 * 别加起来,就是所有页码中t的个数了
 * <br>假定所有n>=1

 * */

class numberCount{
	private int n;
	private int length;
	private int[]result;
	private static void confirm(int n,int[]result){//用于验证的方法,挨个计算每个整数各位上的数
		while(n>0){
			result[n%10]++;
			n/=10;
		}
	}
	public static void test(){//测试函数
		int[]n={9,23,301,3423,34830,1000000,83049839};
		for(int j:n){
			numberCount nc=new numberCount(j);
			int[]result=nc.getCount();
			System.out.println("n="+j);
			for(int t=0;t<10;t++){
				System.out.println("digit="+t+"  number="+result[t]);
			}
			int[]con=new int[10];
			for(int k=1;k<=j;k++)
				confirm(k,con);
			for(int k=0;k<10;k++)
				if(con[k]!=result[k]){
					System.out.println("Error!");
					for(int t:con)
						System.out.println(t);
					break;
				}
		}
	}
	public numberCount(int n){
		this.n=n;
		length=lengthOf();
	}
	/**获取所有页码中0-9每个数字的个数*/
	public int[]getCount(){
		if(result==null){
			result = new int[10];
			result[0] = getZeroCount();
			for (int j = 1; j < 10; j++)
				result[j] = getCount(j);
		}
		return Arrays.copyOf(result, result.length);
	}
	private int getZeroCount(){//计算0的个数,没有前导0,所以这个要单独计算
		int pos=1,tk=10,zeroNumber=0;
		while(pos<length){//0不能在最高位
			zeroNumber+=(n/tk-1)*(tk/10);//没有前导0,所以要减1,后pos-1位构成数的个数是tk/10
			if(pos>1){
				// 考虑pos-1位
				int na = n % tk;
				int second = na * 10 / tk;//pos-1为的数字
				if(second==0){//pos-1为0,则>n/tk*tk的数中符合的个数是na+1个
					zeroNumber+=na+1;
				}else{//若该位不为0,则符合的个数就是pos-1位的所有组合数,即tk/10
					zeroNumber+=tk/10;
				}
			}else{
				zeroNumber+=(n<10?0:1);
			}
			pos++;
			tk*=10;
		}
		return zeroNumber;
	}
	private int getCount(int k){//计算1-9的个数
		int pos=1,tk=10,number=0;
		while(pos<=length){
			number+=n/tk*(tk/10);
			if(pos>1){
				int na=n%tk;
				int second=na*10/tk;
				if(second==k){
					number+=na-k*tk/10+1;
				}else if(second>k){
					number+=tk/10;
				}
			}else{
				number+=n%10>=k?1:0;
			}
			pos++;
			tk*=10;
		}
		return number;
	}
	private int lengthOf(){//计算n的十进制的长度
		int r=0,t=1;
		while(t<=n){
			r++;
			t*=10;
		}
		return r;
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值