题目描述
输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。
示例 1:
输入:n = 12
输出:5
示例 2:
输入:n = 13
输出:6
限制:
1 <= n < 2^31
方法一(按位统计)
1.解题思路
- 可以通过计算每一位为1时有多少种情况(比如个、十、百、千、万),然后把各个位上的情况做一个累加。
- 举例说明:比如1102这个数字,个位为1的情况有(0001,0011,0021,……,1101)共(110+1)*1种,十位为1的情况有(0010,0011,0012,……0019,0110,0111,0112,……0119,1010,1011,1012,……1019)共11*10种,百位为1的情况有(0100,0101,……0199,……1100,1101,1102)共1*100+2+1种,同理千位为1的有102+1种
- 总结:对于1102这个数,在确定某一位后,把它分为high、cur、low三部分,比如确定为个位的时候,high=110,cur=2,low=0。再代入之前总结的规律,当前位为1的总共有(high+1)*i种;同理,当前位等于0的时候,有high*i种,当前位等于1时,有high*i+low+1种。
2.代码实现
class Solution {
public int countDigitOne(int n) {
int res=0;
//i是对应的位数,(比如个,十,百,千,万)
for(long i=1;i<=n;i*=10){
long low=n%i;
long cur=(n/i)%10;
long high=(n/i)/10;
if(cur==0){
res+=high*i;
}
else if(cur==1){
res+=high*i+low+1;
}
else{
res+=(high+1)*i;
}
}
return res;
}
}
3.复杂度分析
- 时间复杂度:循环内的计算操作需要O(1)时间,循环的次数为n中数字个数,即log10n,所以时间复杂度是O(log10n)。
- 空间复杂度:需要额外常数级别的空间,所以空间复杂度为O(1)。
方法二(情况合并)
1.解题思路
注意到当前位大于1时,与其他情况相比,高位系数要加1,所以可以通过加8除10的方式合并所有的情况。
2.代码实现
class Solution {
public int countDigitOne(int n) {
int count=0;
for(long i=1;i<=n;i*=10){
long a=n/i; //当前位+高位组成的数
long b=n%i; //低位数字
count+=(a+8)/10*i+(a%10==1?b+1:0);
}
return count;
}
}
3.复杂度分析
- 时间复杂度:循环内的计算操作需要O(1)时间,循环的次数为n中数字个数,即log10n,所以时间复杂度是O(log10n)。
- 空间复杂度:需要额外常数级别的空间,所以空间复杂度为O(1)。
剑指offer全集入口: 请戳这里