整数中1出现的次数(从1到n整数中1出现的次数)
时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
题目描述
class Solution { public: int NumberOf1Between1AndN_Solution(int n) { if(n < 0) return 0; int count = 0; for(int i =n;i>0;i-- ) { for(int j =i;j > 0;j /=10) { if(j %10 == 1) count++; } } return count; } };
另一种方法就是找出规律,归纳出合理的公式
先固定某位数的值为1,将一个数分为两部分,高位和低位。假设一个五位数n,用m来分割高低位,根据设定的整数位置,对n分割,分为两部分,高位n/m,低位就是n%m,分为三种情况,(再假设m所在位数为百位)
1、当百位数>=2,如n = 31456,m = 100,则高位a = 314,低位b = 56
100 ~ 199
1100~1199
…
31100~31199
此时百位为1 的次数有a/10 + 1 = 32(最高两位0~31),每一次都包含了100~199这100个连续的点,所以共有(a / 10 + 1) * 100个点的百位为1
2、当百位数 ==1,如n = 31156,m = 100,则a = 311,b = 56
100 ~ 199
1100~1199
…
31100~31156
此时百位为1,共有a/10(最高两位0~30)次包含100个连续的点,即(a / 10) * 100 ,再加上局部点00~56,共有b+1次,即总共1的次数为(a/10)* 100 + b+1次
3、当百位数 ==0时,如n=31056,m = 100,则a = 310,b = 56
100 ~ 199
1100~1199
…
31000~31056
一共有(a/10) *100个1
综上三种情况,当百位对于0或者>=2时,有(a+8)/10次包含有100个连续点,还有当百位==1(a%10 ==1)时,需要增加局部点b+1
(之所以加8,是因为当百位数为0,则a / 10 = (a + 8)/10,当百位>=2,加8会产生进位,效果等同于(a/10 + 1),这样就可以将上述三种情况用一个表达式进行表达:
count = (a + 8) // 10 * m + (a % 10 == 1) * (b + 1)
class Solution { public: int NumberOf1Between1AndN_Solution(int n) { if(n < 0) return 0; int i = 1; int count = 0; for(i = 1;i <= n;i*=10) { int a = n/i,b = n%i; count += (a+8)/10*i + (a % 10 == 1)*(b+1); } return count; } };