题目描述
题解一:归纳法
1 /** 2 *个位上1出现的个数为:n/10 * 1+(n%10!=0 ? 1 : 0) 3 *十位上1出现的个数为:(n / 100) * 10 + (if(k > 19) 10 else if(k < 10) 0 else k - 10 + 1) 4 *百位上1出现的个数为:(n / 1000) * 100 + (if(k >199) 100 else if(k < 100) 0 else k - 100 + 1) 5 *设i为计算1所在的位数,i=1表示计算个位数的1的个数,10表示计算十位数的1的个数 6 * k = n % (i * 10) 7 * count(i) = (n / (i * 10)) * i + (if(k > i * 2 - 1) i else if(k < i) 0 else k - i + 1) 8 * 可以把后半段简化成这样,我们不去计算i * 2 - 1了,我们只需保证k - i + 1在[0, i]区间内就行了,最后后半段可以写成这样 9 * min(max(k−i+1,0),i) => min(max((n mod (i*10))−i+1,0),i) 10 */ 11 public static int NumberOf1Between1AndN_Solution(int n) { 12 if(n <= 0) { 13 return 0; 14 } 15 int count = 0; 16 for(long i = 1; i <= n; i *= 10){ 17 long diviver = i * 10; 18 count += (n / diviver) * i + Math.min(Math.max(n % diviver - i + 1, 0), i); 19 } 20 return count;
1 public static int NumberOf1Between1AndN_Solution01(int n) { 2 int count=0; 3 StringBuffer s=new StringBuffer(); 4 for(int i=1;i<n+1;i++){ 5 s.append(i); 6 } 7 String str=s.toString(); 8 for(int i=0;i<str.length();i++){ 9 if(str.charAt(i)=='1'){ 10 count++; 11 } 12 } 13 return count; 14 }
1 /** 2 *只有n的第m位为1时需要计算后缀,后缀计算为 (n/m%10==1)*(b+1), 3 * 即(n/m%10==1)判断第m位是否为1,若为1,则加上(b+1),若不为1,则只计算前缀。 4 * (若计算2的个数,可以改为(n/m%10==2)*(b+1), 5 * 若计算3的个数,可以改为(n/m%10==3)*(b+1)…以此类推) 6 */ 7 public static int NumberOf1Between1AndN_Solution02(int n) { 8 int ones = 0; 9 for(int m=1;m<=n;m*=10){ 10 //挨个获取各个m位的数值 11 int a = n / m; 12 int b = n % m; 13 if(a % 10 == 1){ 14 ones += (a + 8) / 10 * m +b + 1; 15 }else { 16 ones += (a + 8) / 10 * m; 17 } 18 } 19 return ones; 20 }
测试:
1 public static void main(String[] args) { 2 int n=13; 3 int number = NumberOf1Between1AndN_Solution(n); 4 System.out.println(number); 5 } 6 输出:6