题目描述
输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。
例如输入12,从1到12这些整数中包含“1”的数字有1,10,11和12,其中“1”一共出现了5次。
样例
输入: 12
输出: 5
思路一
每次通过对10取余来判断一个数的各个数位上的数字是否为1,逐一对每个数判断,最后加和。
class Solution {
public:
int numberOf1Between1AndN_Solution(int n) {
int cnt = 0;
for(int i = 1; i <= n; ++i)
cnt += cntTimesOne(i);
return cnt;
}
int cntTimesOne(int n){
int res = 0;
while(n){
if(n % 10 == 1)
++res;
n /= 10;
}
return res;
}
};
思路二
每10个数,有一个个位是1,每100个数,有10个十位是1,每1000个数,有100个百位是1。
在循环中,每次计算单个数位上1的个数(个位,十位,百位…)。
以计算百位上出现1的个数为例:
令
a
=
n
/
k
a = n / k
a=n/k,
b
=
n
%
k
b = n \% k
b=n%k,
k
=
1
,
10
,
100...
且
k
<
=
n
k = 1, 10, 100... 且 k <= n
k=1,10,100...且k<=n
假设百位上为0, 1, 和 >=2 三种情况:
case 1:n=3141092,a= 31410,b=92。百位上1的个数应该为 3141 *100 次
case 2:n=3141192,a= 31411,b=92。百位上1的个数应该为 3141 *100 + (92+1) 次
case 3:n=3141592,a= 31415,b=92。百位上1的个数应该为 (3141+1) *100 次
以上三种情况可以用 一个公式概括:
(
a
+
8
)
/
10
∗
m
+
(
a
%
10
=
=
1
)
∗
(
b
+
1
)
(a + 8) / 10 * m + (a \% 10 == 1) * (b + 1)
(a+8)/10∗m+(a%10==1)∗(b+1)
class Solution {
public:
int countDigitOne(int n) {
int res = 0;
for (long k = 1; k <= n; k *= 10) {
long a = n / k, b = n % k;
res += (a + 8) / 10 * k + (a % 10 == 1 ? b + 1 : 0);
}
return res;
}
};