题目描述
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
我是这样拆分的:
首先是有规律的,比如当前数为n,则N的范围如下是,1的数量如下
0~9:只有1个,0到9只存在1个1。
10~19:拆分为0到9,和10到N。1+N+1;
20~99:比如N=33,则拆分为4*1 和10到19(不包含11中的第二个1)。其中0到99为20
100~109:拆分为0到99和100到N
110~119:拆分为0到99,100到109,110到N
120~199:拆分为0到99,110到119(同样不包含最前面的1),100到N
200~999:比如351,拆分为0到299,300到349,350到351。
举个实际例子,3135,
先求3130到3135,只算个位的,为1;
再求十位的,为3,则个位上出现次数为3,十位上的出现次数为10,则和为13。0到99为20次。
在求百位的,为1,则先求0到99的出现次数为20,加上百分位上出现的次数35,加上100出现的次数1,则和为56。0到999为300次
最终求千分位上的,为0到999出现了三次,则为3*300次,以及1000到1999上千分位上的1的次数,求和为1900。
import java.util.*;
import java.util.function.Supplier;
public class Test {
static int maxLevel = 0;
public static void main(String[] args) {
int i = new Test().NumberOf1Between1AndN_Solution(103);
System.out.println(i);
}
HashMap<Integer, Integer> map = new HashMap<>();
public int NumberOf1Between1AndN_Solution(int n) {
int mask = 1;
int figure = 1;
int last = 0;
int times = 0;
while (n / mask > 0) {
int current = n / mask % 10;
times += getTimes(n, figure++, current, last, mask);
last = current;
mask = mask * 10;
}
return times;
}
/**
* @param figure 几位
* @param current 当前位值
* @param mask 掩码
* @return
*/
private int getTimes(int n, int figure, int current, int last, int mask) {
int times = 0;
Integer lasttime = map.get(figure - 1);
if (lasttime == null) {
lasttime = 0;
}
if (current == 0) {
} else if (current == 1) {
times = lasttime + n % mask + 1;
} else {
times = current * lasttime + mask;
}
map.put(figure, lasttime * 10 + mask);
System.out.println("figure:" + figure + ",current:" + current + ",last:" + last + ",mask:" + mask + ",times:" + times);
return times;
}
}