https://leetcode.com/problems/number-of-digit-one/
Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.
For example:
Given n = 13,
Return 6, because digit 1 occurred in the following numbers: 1, 10, 11, 12, 13.
Hint:
- Beware of overflow.
如果不用暴力求解,显然需要找寻规律
方法一
拿n=21345作为例子分析:
可以将n分为三部分:0-(0)1345,1346-11345和11346-21345
第一部分0-(0)1345可以递归求解21345-20000得结果
第二、三部分分别求(设n最高位是n0)
小于n中当最高位为1得,一共出现10000-19999共10000次,这是因为n0=2,如果n0=1(如11345),则出现11345-10000+1次
剩下分析除n0外其它四位情况,后四位可以任选一位是1,其余可以在0-9选择。因此是4*1000次,因为是两部分,所以*2
更详细分析参考《剑指Offer》P175
int countDigitOne(int n)
{
if (n < 1)
return 0;
int n0, len,res = 0,num;//n0记录最高位,len记录位数
while (n>0)
{
if (n < 10)
{
res++;
break;
}
n0 = n;
len = 0;
while (n0 / 10 > 0)
{
n0 /= 10;
len++;
}
num = pow(10, len);
if (n0 == 1)//计算最高位出现1个个数
res += n - num + 1;
else
res += num;
res += n0*len*(num / 10);//括号是防止溢出
n -= n0*num;
}
return res;
}
方法二、
分别讨论每一位为1的情况
参考 https://discuss.leetcode.com/topic/18054/4-lines-o-log-n-c-java-python
int countDigitOne(int n)
{
int res = 0, a, b;
for (long m = 1; m <= n; m *= 10)
{
a = n / m;
b = n % m;
res+= (a + 8) / 10 * m + (a % 10 == 1) * (b + 1);
}
return res;
}
例:
以百位上1为例子: 假设百位上是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);