剑指Offer——计算1至n中数字x出现的次数

来源:互联网 发布:怎样查看追加淘宝评价 编辑:程序博客网 时间:2024/06/05 21:29

一、1的数目

编程之美上给出的规律:

1. 如果第i位(自左至右,从1开始标号)上的数字为0,则第i位可能出现1的次数由更高位决定(若没有高位,视高位为0),等于更高位数字乘以当前位数的权重10^(i-1)。

2. 如果第i位上的数字为1,则第i位上可能出现1的次数不仅受更高位影响,还受低位影响(若没有低位,视低位为0),等于更高位数字乘以当前位数的权重10^(i-1) + (低位数字+1)。

3. 如果第i位上的数字大于1,则第i位上可能出现1的次数仅由更高位决定(若没有高位,视高位为0),等于(更高位数字+1)乘以当前位数的权重10^(i-1)。

二、X的数目

这里的X∈[1, 9],因为X=0不符合下列规律,需要单独计算。

首先要知道以下规律:

  • 从1至10,在它们的个位数中,任意的X都出现了1次。
  • 从1至100,在它们的十位数中,任意的X都出现了10次。
  • 从1至1000,在它们的百位数中,任意的X都出现了100次。
以此类推,从1至10^i,在它们的左数第二位(右数第i位)中,任意的X都出现了10^(i-1)次。
这个规律很容易验证,这里不再多做说明。
接下来以n=2593,X=5为例来解释如何得到数学公式。从1至2593中,数字5总计出现了813次,其中有259次出现在个位,260次出现在十位,294次出现在百位,0次出现在千位。
现在依次分析这些数据,首先是个位。从1至2590中,包含了259个10,因此任意的X都出现了259次。最后剩余的三个数2591、2592和2593,因为它们最大的个位数字3<X,因此不会包含任何5。(也可以这么看,3<X,则个位数上可能出现的X的次数仅由更高位决定,等于更高位数字(259)×10^(1-1)=259)。
然后是十位。从1至2500中,包含了25个100,因此任意的X都出现了25×10=250次。剩下的数字是从2501至2593,它们最大的十位数字9>X,因此会包含全部10个5。最后总计250+10=260。(也可以这么看,9>X,则十位上可能出现的X的次数仅由更高位决定,等于更高位数字(25+1)×10^(2-1)=260)。
接下来是百位。从1至2000中,包含了2个1000,因此任意的X都出现了2×100次。剩下的数字是从2001至2593,它们最大的百位数字5==X,这时情况就略微复杂,它们的百位肯定是包含5的,但不会包含全部100个。如果把百位是5的数字列出来,是从2500至2593,数字的个数与百位和十位数字相关,是93+1=94。最后总计200+94=294。(也可以这么看,5==X,则百位上可能出现X的次数不仅受更高位影响,还受低位影响,等于更高位数字(2)×10^(3-1)+(93+1)=294)。
最后是千位。现在已经没有更高位,因此直接看最大的千位数字2<X。所以不会包含任何5。(也可以这么看,2<X,则千位上可能出现的X的次数仅由更高位决定,等于更高位数字(0)×10^(4-1)=0)。
到此为止,已经计算出全部数字5的出现次数。
总结一下上面的算法,可以看到,当计算右数第i位包含的X的个数时:
  1. 取第i位左边(高位)的数字,乘以10^(i-1),得到基础值a。
  2. 取第i位数字,计算修正值:如果大于X,则结果为a+10^(i-1);如果小于X,则结果为a;如果等于X,则取第i位右边(低位)数字,设为b,最后结果为a+b+1。
相应的代码也非常简单,效率也非常高,时间复杂度只有O(lgn)。
public class NumberOfXBetween1AndN {public int numberOfXBetween1AndN(int n, int x) {if(n < 0 || x < 1 || x > 9)return 0;int high, low, curr, tmp, i = 1;high = n;int total = 0;while(high != 0) {high = n / (int)Math.pow(10, i); // 获取第i位的高位tmp = n % (int)Math.pow(10, i);curr = tmp / (int)Math.pow(10, i-1); //获取第i位low = tmp % (int)Math.pow(10, i-1); //获取第i位的低位if(curr == x)total += high*(int)Math.pow(10, i-1) + low + 1;else if(curr > x)total += (high+1)*(int)Math.pow(10, i-1);elsetotal += high*(int)Math.pow(10, i-1);i++;}return total;}}




阅读全文
0 0
原创粉丝点击