剑指Offer之从1到n整数中1出现的次数
题目描述
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。
基本思路
当计算右数第$i$位包含的1个数时,1、取第$i$左边(高位)的数字,乘以$10^{i-1}$,得到基础数值a;2、取第$i$位数字计算修正值:
- 如果大于1,则结果为a+$10^{i-1}$
- 如果小于1,则结果为a
- 如果等于1,则取第$i$位右边(低位)的数字设为b,则结果为a+b+1
此算法的时间复杂度为$O(log_{10}n)$
Java代码
package com.swordOffer.numberOfOne23;
import java.util.Scanner;
/**
* Created by Feng on 2017/5/27.
* 求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?
* 为此他特别数了一下1~13中包含1的数字有1、10、11、12、13
* 因此共出现6次,但是对于后面问题他就没辙了。
* ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。
*/
public class NumberOfOne {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
int inputNum = sc.nextInt();
int result = numberOfOne(inputNum);
System.out.println(result);
}
}
private static int numberOfOne(int inputNum) {
//统计1的个数
int count = 0;
//表示当前数字
int curNum = 0;
//表示低位
int lowNum = 0;
//表示高位
int highNum = 0;
//表示因子
int factor = 1;
while (inputNum / factor != 0) {
// 12345对10取余,相当于将当前数置为个位
curNum = (inputNum / factor) % 10;
lowNum = inputNum % factor;
highNum = inputNum / (factor * 10);
//如果为0,出现1的次数由高位决定,等于高位数字 * 当前位数
if (curNum == 0) {
//表示10,101的情况
count += factor * highNum;
} else if (curNum == 1) {
//如果为1,出现1的次数由高位和低位决定,高位*当前位+低位+1
count += factor * highNum + lowNum + 1;
} else {
//如果大于1,出现1的次数由高位决定,
//高位数字+1* 当前位数
count += factor * (highNum + 1);
}
factor *= 10;
}
return count;
}
}