JZ31 - 整数中1出现的个数(从1到n整数中1出现的次数)
题目:求出1-13的整数中1出现的次数,并算出100-1300的整数中1出现的次数?为此他特别数了一下1-13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
解题思路:
- 将n分成高位和低位两部分,从各位开始、十位、百位…进行分割,十位以上思想相同,这里拿十位和个位说区别;
- 个位:有2种情况,第一种只要个位大于等于1就可以增加一个1;第二种是0没有1,例如1-71中个位有8个1,70中个位有7个1,即(x+9)/10 1即可解决;
- 十位:有3中情况,第一种为0,没有1;第二种等于1,这样这块的数字就由低位数字决定个数了,例如1-17中十位有8个1(数量为低位数字7+1);第三种情况大于等于2,十位就包含10个1,例如(20中十位有10个1,120中十位有20个1)在这两个例子中高为分别为2和12,即(x+8)/10*10即可;
- 百位、千位…同十位处理方法一样。
- 这里将十位中的(x+8)和个位中的(x+9)做一下统一,个位末尾大于等于1的情况是不是可以看成十位中的第二种情况和第三种情况呢,为1时只不过低位为0,低位+1还是1 。而大于等于2时直接(x+8)/10 *1也可以加1 。这样就将所有位置都统一了,代码如下:
/**
* @author 枫叶火火
*/
public class Solution {
public int NumberOf1Between1AndN_Solution(int n) {
//1的数量
int num = 0;
//每次增长一位
for(int i = 1 ; i <= n ; i*=10){
//分割数字
//高位
int high = n / i;
//低位,i代表个位时,个位下面对1取余就是0
int low = n % i;
//先计算整的,高位最后一位达到2就可以进位,当前位就有乘i个1,这里达到1但是每到2的另算,数量和低位有关
num +=(high + 8)/10 * i;
//当高位的最后一位为1就是上面说的那种情况,就应该再加上这几个当前位带有1的数量也就是低位+1(10~16只看10位有7个1)
if(high % 10 == 1){
num += low + 1;
}
}
return num;
}
}