(剑指Offer)整数中1出现的次数(从1到n整数中1出现的次数)

题目描述
求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

C++跟java的不同在于,C++可以直接通过指针去操作内存里面的东西,但是Java需要通过借助数组去实现,对于数组的访问C++直接指针上面加减便可以,但是Java需要借助数组的下标。

复杂度比较高的办法

对输入的每个数字进行判断,然后累加结果。

 public  int NumberOf1Between1AndN_Solution(int num){
	if(num <= 0) return 0;
	int count = 0;
	for(int i=1;i<=n;i++){
		count += counNumOf1(i);
	}
	return count;
}
public int countNum(int n){
	int result = 0;
	while(n>0){
		int mod = n%10;
		if(mod == 1){
			result++;
		}
		n = n/10;
	}
	return result;
}

时间复杂度为O(logn) 虽然书上这么说,但是由于Java里面没有C++的aoti的方法,所以我觉得复杂度是o(nlogn)

思路主要是:1 - 21345分解为1346 - 21345和1-1345 再把1346-11345,11346-21345这样做的目的是为了保证四位数里面可以从1000-9999都可以实现。
而终止条件为:当长度为1的时候判断最后最后一位,如果是0返回0,如果大于0返回1.

  1. 先判断最高位为1共有多少个。具体的判断的方法为如果最高位大于1的话,说明包含最高位为1的个数为Math.pow(10,length);length表示数字的总的长度,如果最高位为1的话,那么个数位,除去最高位以后的数字+1个
  2. 判断除去最高位以后还有多少个1,这个时候就可以数一下除去最高位的位数为n,第一位为first证明这里面有几个区间,然后后面的位数都可以从0-9随机选择,nfirstMath.pow(10,n-1)
  3. 然后去递归的找,除去最高位的数字以后剩余的内容。
    具体的实现的代码:
 public  int NumberOf1Between1AndN_Solution(int num){
		if(num <= 0) return 0;
		char[] arr = String.valueOf(num).toCharArray();
		return findNumberOf1(arr,0,arr.length);
	}
	public  int findNumberOf1(char[] arr,int index,int length){

		int first = arr[index] - '0';
		if(length == 1 && first == 0){
			return 0;
		}
		if(length == 1 && first > 0){
			return 1;
		}
		int highNum = 0;
		if(first >1){
			highNum = (int)Math.pow(10,length-1);
		}else if(first == 1){
			highNum = countHighNumOf1(arr,index);
		}
		int exceptHighNumOf1 = first*(length-1)*(int)(Math.pow(10,length-2));
		int leftNumOf1 = findNumberOf1(arr,index+1,length-1);
		return highNum+exceptHighNumOf1+leftNumOf1;
	}
	public  int countHighNumOf1(char[] arr,int index){
		String s = "";
		for(int i=index+1;i<arr.length;i++){
			s += arr[i];
		}
		int result = Integer.valueOf(s);
		return result + 1;
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值