描述:计算 1 至 n 中数字 X 出现的次数,其中 n≥1,X∈[0,
n≥1,X∈[0,9]
n≥1,X∈[0,9]
n≥1,X∈[0,9]
1.1 考虑x范围为1~9:
首先要总结不同位置情况下,X出现的个数:
1. 从1至10,X在个位出现1次
2. 从1至100,X在十位出现10次
3. 从1 至1000,X在百位出现100次
...……
结论:从1至10^i, X在第i位出现10^(i-1)次 //(i为从右至左)
而当计算第i位包含x的个数时,还需分别考虑第i位大于、小于、等于x时的情况,故总结如下:
1. 取所有不低于第i位的数字,乘以10^(i-1),得到基值a
2. 取第i位数字,计算修正值:
1)若大于x,结果为 a+10^(i-1)
2) 若等于x,取低于第i位数字b,结果为 a + b + 1
3)若小于x,结果为 a
故当X不为0时,代码如下:
class Solution {
public:
int NumberOfxBetween1AndN_Solution(int n, int x)
{
int sum = 0, k;
for(int i=1; k = n / i; i *= 10)
{
sum += k / 10 * i;
int cur = k % 10;
if(cur > x) sum += i;
else if(cur == x) sum += n - k * i + 1;
}
return sum;
}
};
1.2 单独考虑 x = 0
x = 0 时与上述情况的区别是:
1. 从个位累加到次高位就应结束(最高位不会包括零)
2. 第i位的基础值为高位数字乘以 10^(i-1) - 1(从1~10,数字0在个位出现0次)
当x等于0时,代码如下:
class Solution {
public:
int NumberOfxBetween1AndN_Solution(int n, int x)
{
int sum = 0, k;
for(int i=1; (k = n / i) / 10; i *= 10)
{
sum += (k / 10 - 1) * i;
int cur = k % 10;
if (cur > x) sum += i;
else if (cur == x) sum += n - k * i + 1;
}
return sum;
}
};
可化简为:
class Solution {
public:
int NumberOfxBetween1AndN_Solution(int n)
{
int sum = 0, k;
for(int i=1; (k = n/i) / 10; i *= 10)
{
sum += k / 10 * i ;
if( k % 10 == 0) sum += n - k * i + 1 - i;
}
return sum;
}
};
综上,将两种情况合并,代码如下:
class Solution {
public:
int NumberOfxBetween1AndN_Solution(int n, int x)
{
int sum = 0, k;
for(int i=1; k = n / i; i *= 10)
{
int high = k / 10 ;
int low = k % 10;
if(x==0) {
if(high) high--;
else break;
}
sum += high * i;
if(low > x) sum += i;
else if(cur == x ) sum += n - k * i + 1;
}
return sum;
}
};
参考文章:http://www.cnblogs.com/cyjb/p/digitOccurrenceInRegion.html