题目描述
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
那种简单的嵌套双遍历这里就不讲了,说一下另一种思路,使用归纳法总结套路公式老解决。
1、个位1出现的次数:
个位来说1出现的次数会每隔10出现一次,1、11、21、31...所以个位1出现的次数为n/10,但是输入的数字可能不是像1、11这种理想的数字可能会多出一部分,如题目所述的13,这时候如果多出来了11~13可能就需要单独算出来,然后累加到前面的结果。所以有:
k=n%10;
count = n/10+ if(k!=0)1 else 0
2、十位1出现的次数:
十位为每隔100位数出现一次,10,110,210...所以十位1出现的次数为n/100,同上,如果出现多出的情况,则需要累加多余的符合条条件的结果,得出:
k=n%100;
count = (n/100)*10+if(k>19) 10 else if(k<10) 0 else k -10+1
3、百位1出现的次数:
百位每隔1000位数出现一次,100,1100,2100...所以百位1出现的次数n/1000,跟个位相同,出现多出的情况,则累加:
k=n%1000;
count = (n/1000)*100+if(k>199) 100 else if(k<100) 0 else k -100+1
通过上边我们可以总结出:
i范围为10~log10(n)
k=n%(10*i)
count = (n/(10*i))*i+if(k>10*i-1) i else if(k<0)0 else k-i+1
最后使用Math的min与max替换if else的操作
import java.util.*;
public class Solution {
public int NumberOf1Between1AndN_Solution(int n) {
if(n<=0)return 0;
int count = 0;
for(long i =1;i<=n;i*=10){
long tem = i*10;
count +=(n/tem)*i + Math.min(Math.max(n%tem-i+1,0),i);// 保证k-i+1在[0,1]内,其实就是用Math替换掉了if和else if
}
return count;
}
}