清奇思路(六)从1到n整数中1出现的次数

1.题目描述

  1. 1~13中包含1的数字有1、10、11、12、13,因此“1”共出现6次;
  2. 求出任意非负整数区间中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”的个数至少有 31 100

这个100是由于百位本身的特性决定的,因此如果我们记X所在的位权重为Base,如下图所示:
这里写图片描述
那么,百位上“1”至少出现的次数就是: R o u n d B a s e .


2.1.2 如果X>1(即X为2~9)

这里我们应该也知道,在第32轮,也就是Round为31的时候,只有31100 - 31199百位上会出现“1”。
所以如果 X > 1 ,那就是看 100 199 有多少个“1”。因此,如果X>1,百位上“1”的个数有 31 100 + 1 100

那么,此时百位上“1”出现的次数就是: ( R o u n d + 1 ) B a s e .

2.1.3 如果X==0

在第32轮,也就是Round为31的时候,只有31100 - 31199百位上会出现“1”。所以,如果 X == 0 ,那就是看 31000 31056 有多少个“1”。很明显没有。

那么,此时百位上“1”出现的次数就是: ( R o u n d ) B a s e .

2.1.4 如果X==1

在第32轮,也就是Round为31的时候,只有31100 - 31199百位上会出现“1”。所以,如果 X == 1 ,那就是看 31100 31156 有多少个“1”。取决于百位后面的数字是多少。
如果我们记百位后面的数字为Former,如图所示:
这里写图片描述
那么,此时百位上“1”出现的次数就是: ( R o u n d ) B a s e + F o r m e r + 1 .

2.2用公式写出来

1. R o u n d = N / B a s e / 10
2. F o r m e r = N / B a s e
百位上“1”出现的次数就是:
R o u n d + ϵ ( X 1 ) ) B a s e + F o r m e r + 1 δ ( X 1 )

其中, ϵ ( X ) δ ( X )

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。不会影响到个位整体计算公式的。

猜你喜欢

转载自blog.csdn.net/wushuomin/article/details/80212910