剑指offer第二版——面试题43(java)

该博客详细介绍了如何计算1到n整数中1出现的次数,通过分析数的十进制表示,分为三种情况讨论:x>1, x=1, x=0,并给出了相应的计数公式。方法适用于计算任意数字在1到n中出现的次数,而对于0的出现次数计算稍有不同。" 107599517,9801330,JavaScript监听网页:鼠标与键盘事件详解,"['JavaScript', 'event', 'HTML5']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

面试题:1~n整数中1出现的次数

题目:

输入一个整数n,求1~n这n个整数的十进制表示中1出现的次数。

如输入12,1~12这些整数中包括1的数字有1、10、11和12,1一共出现了5次

【思路】

剑指offer上的解释有点看不懂囧,参考:https://www.cnblogs.com/wangkundentisy/p/8946858.html

对于一个形如xxxx的数,如要计算1出现在十位的数的个数,即xx1x的个数,分为三种情况

① xxab,a>1

a>1时,令a=1,则无论前面的两位xx取什么,都有相应的10个数可与之组合(如前面取23,后面可有10~19与其组合为2310~2319)

此时的数的取值为(xx+1)*10^(2-1)  ——xx+1是因为,若xx为22,则可从0开始取值,一直到22,实际是23个取值;10^(2-1)是因为在十位上时,位置标志为2,然而与之相对应的只有10个数,需要2-1

② xxab,a=1

a=1时,a只有一种取值,即1,且受后面b的影响,与①的区别主要在于:当xx取到最高时(如2315时,23固定后,只能从10~15=6个数,而2325可从10~19=10个数),不再是10个数都是可取的,因此,分开计算

此时数的取值为(xx)*10^(2-1)+(b+1) ——前面xx其实是代表的xx-1+1,指的是从0开始取值,直到最高位-1(xx-1),当xx取最高位时,后面只能取10~1b——b+1个数

③ xxab,a=0

a=0时,xx0b,此时xx只能取到0~(xx-1)——共xx种取值,每种取值对应10^(2-1)个数

此时数的取值为(xx)*10^(2-1) ,当xx取最高位时,十位上无法出现1(因为超过了数本身)

【方法】

所以总的来说,对于从右到左数的第i位(位上数为x),出现1的次数为:

① x>1,(高位+1)*10^(i-1) 

② x=1,(高位)*10^(i-1)+(低位+1)

③ x=0,(高位)*10^(i-1)

public class Q43 {
	public static void main(String[] args) {
		int a = 10000;
		System.out.println(howManyOne(a));
		
		
	}

	public static int howManyOne(int x) {
		// 如果是个位数,只出现1次
		if(x<10) {
			return 1;
		}
		int left = 0;
		double count = 0;
		int re = x;
		int sum = 0;
		while(re!=0) {
			left = re%10;
			re = re/10;
			
			// 当前位的数字==1
			if(left==1) {
				sum = (int) (sum + re*Math.pow(10, count)+x%Math.pow(10, count+1));
			
			// 当前位的数字==0
			}else if(left==0) {
				sum = (int) (sum + re*Math.pow(10, count));
				
			// 当前位的数字>1
			}else {
				sum = (int) (sum + (re+1)*Math.pow(10, count));
			}
			count++;
		}
		return sum;
	}
}

【其他】

如果要计算其他数字出现的次数也是相同的,只是把用于比较的1改为该数(1~9)即可

如果要计算0出现的次数,会有所不同,在最后需要把当0出现在第一位的次数减掉

	public static int howManyZero(int x) {
		// 如果是个位数,只出现1次
		if(x<10) {
			return 1;
		}
		int stad = 0;
		int left = 0;
		double count = 0;
		int re = x;
		int sum = 0;
		while(re!=0) {
			left = re%10;
			re = re/10;
			
			// 当前位的数字==0
			if(left==stad) {
				sum = (int) (sum + re*Math.pow(10, count)+x%Math.pow(10, count+1));
			
			// 当前位的数字!=0
			}else {
				sum = (int) (sum + (re+1)*Math.pow(10, count));
			}
			count++;
		}
		return sum-(int) ((re+1)*Math.pow(10, count-1));
	}

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值