学习下如何统计【0-9】在任意给定数中出现的次数

来源:互联网 发布:数据交换技术要求 编辑:程序博客网 时间:2024/06/05 15:23

总结一下以上的算法,可以看到,当计算右数第 i 位包含的 X 的个数时:

  1. 取第 i 位左边(高位)的数字,乘以 10i1,得到基础值 a
  2. 取第 i 位数字,计算修正值
    1. 如果大于 X,则结果为 a+10i1
    2. 如果小于 X,则结果为 a
    3. 如果等 X,则取第 i 位右边(低位)数字,设为 b,最后结果为 a+b+1

相应的代码非常简单,效率也非常高,时间复杂度只有 O(log10n)

public static int count1(int givenNumber, int searchKey){
//cnt计数器,初始k为大于0的数
int cnt = 0, k=1;
//i是factor,用来得到每个位置上的数字
   for (int i = 1;k>0;i *= 10) {
    //通过k知道每一位上的基本出险次数
    k = givenNumber / i;
       cnt += (k / 10) * i;
       //当前位上的数字
       int cur = k % 10;
       if (cur > searchKey) {
           cnt += i;
       } else if (cur == searchKey) {
        //第i位的低位加上1
           cnt += givenNumber - k * i + 1;
       }
   }
   return cnt;
}


当 X = 0 时,规律与上面给出的规律不同,需要另行考虑。

最主要的区别是,最高位中永远是不会包含 0 的,因此,从个位累加到左起第二位就要结束,需要将上面代码中 for 循环的判断条件改为 k / 10 != 0。

其次是,第 i 位的基础值不是高位数字乘以 10i1,而是乘以 10i11。以 1 至 102 为例,千位中实际包含 3 个 0,但这三个 0 是来自于个位 2 计算得到的修正值,而非来自于基础值。千位的基础值是 0,因为不存在数字 01, 02, 03, ..., 09,即数字前是没有前导 0 的。解决办法就是将上面代码中第 6 行改为 cnt += (k / 10 - 1) * i。

public static int count(int n, int x) {
   int cnt = 0, k=1;
   for (int i = 1;k>0;i *= 10) {
       // 高位的数字。
    k = n / i;
       int high = k / 10;
       if (x == 0) {
           if (high!=0) {
               high--;
           } else {
               break;
           }
       }
       cnt += high * i;
       // 当前位的数字。
       int cur = k % 10;
       if (cur > x) {
           cnt += i;
       } else if (cur == x) {
           // n - k * i 为低位的数字。
           cnt += n - k * i + 1;
       }
   }
   return cnt;
}
0 0
原创粉丝点击