输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。
例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。
示例 1:
输入:n = 12
输出:5
示例 2:
输入:n = 13
输出:6
原题出处:https://leetcode-cn.com/problems/number-of-digit-one/
算法1:把每个数字中包含1的数量计算出来,然后把1~n的1的数量全部加起来(效率低)
int NembOf1(int n)
{
int ans = 0;
while (n)
{
if (n % 10 == 1)
ans++;
n /= 10;
}
return ans;
}
int NembOf1BetweenN(int n)
{
int ans = 0;
for (int i = 1;i <= n;i++)
{
ans += NembOf1(i);
}
return ans;
}
算法2:看见他人分享的https://leetcode-cn.com/problems/number-of-digit-one/solution/c-kan-dao-bie-ren-fen-xiang-de-by-coke-10/.
编程之美上给出的规律: 1.如果第i位(自右至左,从1开始标号)上的数字为0,则第i位可能出现1的次数由更高位决定(若没有高位,视高位为0),等于更高位数字X当前位数的权重10^(i-1)。 2.如果第i位上的数字为1,则第i位上可能出现1的次数不仅受更高位影响,还受低位影响(若没有低位,视低位为0),等于更高位数字X当前位数的权重10^(i-1)+(低位数字+1)。 3.如果第i位上的数字大于1,则第i位上可能出现1的次数仅由更高位决定(若没有高位,视高位为0),等于(更高位数字+1)X当前位数的权重10^(i-1)。
通用结论:
从 1 至 10,在它们的个位数中,任意的 X 都出现了 1 次
从 1 至 100,在它们的十位数中,任意的 X 都出现了 10 次
从 1 至 1000,在它们的千位数中,任意的 X 都出现了 100 次
依此类推,从 1 至 10^i,在它们的左数第二位(右数第 i 位)中,任意的 X 都出现了10^(i−1) 次
得出的算法如下:
当计算右数第 i 位包含的 X 的个数时:
取第 i 位左边(高位)的数字,乘以 10^(i−1),得到基础值 a
取第 i 位数字,计算修正值:
如果大于 X,则结果为 a+10^(i−1)
如果小于 X,则结果为 a
如果等 X,则取第 i 位右边(低位)数字,设为 b,最后结果为 a+b+1
class Solution {
public:
int countDigitOne(int n) {
if(n<1) return 0;
int res=0,digit=1;
int right=0,now,left;
while(n){
now=n%10;
left=n/10;
if(now<1){
res+=left*pow(10,digit-1);
}
else if(now==1){
res+=left*pow(10,digit-1)+right+1;
}
else{
res+=(left+1)*pow(10,digit-1);
}
right+=pow(10,digit-1)*now;
digit++;
n/=10;
}
return res;
}
};