1.题目描述
- 1~13中包含1的数字有1、10、11、12、13,因此“1”共出现6次;
- 求出任意非负整数区间中1出现的次数。
首先需要说明的是:题目要求的是“1”的个数而不是含1的数字的个数,也就是说对于数字“11”,是有有两个“1”的。是要算两次的!!!!
2. 清奇思路:如何找数字规律判断每一位有几个“1”
牛客网该题目下咩咩jiang的回答由于没有图,字也挤在一起-_-||,原谅我第一次真的看不进去。
博客:yi_Afly的专栏中从1到n整数中1出现的次数图文并茂,讲解的很清楚,思路上和上面的大佬是相近的,建议先看yi_Afly
的再回看咩咩jiang
的,可能会稍稍好一些。
下面开始是我整理两位的发言,梳理的比较有逻辑一点。
2.1 举例子找规律
yi_Afly
从个位开始讲解,但是最终仍然回归到一样的代码上去,因此本文这里先和咩咩jiang
一样,以百位为例,说明如何计算,然后再说明为什么个位计算方法可以与百位的相同。
我们以数字 3 1 X 5 6 为例 //X表示百位数字不定(0~9)均有可能
2.1.1百位为例,百位上至少有多少个“1”
我们用一个Round变量表示百位之前更高位所留存的数字。
那么,很明显可以知道,不管X是多少,在Round从0~30轮中,百位上有“1”的次数至少是31次,因为百位每一次出现“1”需要持续100次(100-199),因此百位上“1”的个数至少有
。
这个100是由于百位本身的特性决定的,因此如果我们记X所在的位权重为Base,如下图所示:
那么,百位上“1”至少出现的次数就是:
.
2.1.2 如果X>1(即X为2~9)
这里我们应该也知道,在第32轮,也就是Round为31的时候,只有31100 - 31199
百位上会出现“1”。
所以如果
,那就是看
有多少个“1”。因此,如果X>1,百位上“1”的个数有
。
那么,此时百位上“1”出现的次数就是: .
2.1.3 如果X==0
在第32轮,也就是Round为31的时候,只有31100 - 31199
百位上会出现“1”。所以,如果
,那就是看
有多少个“1”。很明显没有。
那么,此时百位上“1”出现的次数就是: .
2.1.4 如果X==1
在第32轮,也就是Round为31的时候,只有31100 - 31199
百位上会出现“1”。所以,如果
,那就是看
有多少个“1”。取决于百位后面的数字是多少。
如果我们记百位后面的数字为Former,如图所示:
那么,此时百位上“1”出现的次数就是:
.
2.2用公式写出来
其中,
2.3代码表示
int NumberofOnes(int n)
{
int count = 0;
long long base = 1;
for(base =1;base<=n;base*=10)
{
int Round = n/base;
int X = Round%10;
Round/=10;
int Former = n%base;
count=count+(Round*base+(X>1)*base+(Former+1)*(X==1))
}
return count;
}
当然,根据上述思路还有一些其他的代码表示,也很精妙,但是我个人觉得不如我这个来的直观。
最后说一说为什么个位也可以用,因为个位的Former为0。不会影响到个位整体计算公式的。