题目描述
求出1 ~ 13的整数中1出现的次数,并算出100 ~ 1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
思路分析
1、暴力求解法:这是最容易想到的,即从1到n遍历一遍,对其中的每一个整数都进行求模与取余计算,判断其中的每一位是否为1,并进行相应的计数。
下面是用Java实现的代码供参考:
public class Solution {
public int NumberOf1Between1AndN_Solution(int n) {
int num = 0;
int temp;
for (int i = 1; i <= n; i++) {
temp = i;
while (temp != 0) {
if (temp % 10 == 1) {
num ++;
}
temp /= 10;
}
}
return num;
}
}
2、数学归纳法:
在这里我们任意取一个数来举例说明:比如n=389
百位:该位置上的数字是3(>1),说明之前的百位数为1的数都能取到,所以1的个数是100-199一共有100个;(这里的3是最高位,那么就只有一种可能,可以看做是(0+1)种可能)。
十位:该位置上的数字是8(>1),说明十位上为1的数都可以取到的,而这里需要注意的是,前面 百位上的数字是3,那么百位上的取值可能就是[0,1,2,3],即(3+1)种可能,而每一种可能对应着10-19这10个数,所以1的个数是10*4=40个;
个位:该位置上的数字是9(>1),说明个位上为1的数字是可以取到的,那么前面需要注意前面的数字是38,那么前面的取值就是[38,37,…,1,0],一共39(38+1)种可能,即出现39次1.
综上所述:一共是100+40+39=179次。
还有一些其他情况:比如当前位置上的数字是1,那么就不能只是判断之前位置上的取值可能,还需要判断当前位置之后的取到什么数字:n=216,十位为1,百位为2,那么取值可能是[0,1,2],但是我也需要判断16取到了10-19的什么位置,即16-10+1;即2*10+16-10+1。
再比如当前位置的数字是0,例n=206;那么取值可能是[0,1,2],但是百位取到2的时候是不存在1的,那么就是只有两种可能[0,1],即2*10。
所以综上所述,可能分为三种情况来处理:当前位置是>1,==1,==0。
下面是Java版本的代码实现:
public class Solution {
public int NumberOf1Between1AndN_Solution(int n) {
int count = 0;
int temp = n;
int i = 1;
while (temp != 0) {
int mod = temp % 10; //当前位置上的数字
temp = n / (10 * i); // 当前位置之前的数字
int mod1 = n % (10 * i); //从当前位置之后的数字,包括当前位置的数字
if (mod > 1) {
count += (temp + 1) * i;
} else if (mod == 1) {
count += (temp * i + mod1 - i + 1);
} else {
count += temp * i;
}
i *= 10;
}
return count;
}
}