页码统计解题报告

这里写图片描述

题目要求统计09每个数字出现的次数,可以基于经典题(统计1n1的个数)来求解。

首先给出几个概念:
- 当前数位currNum,低位数字构成的数lowerNum,高位数字构成的数upperNum。引入它们的原因是对于当前数位,它能放置1的个数由这三个数确定。对于n=12345,若currNum=3,则lowerNum=45upperNum=12
- 数位标志数digitPosdigitPos=1表示个位,digitPos=10表示十位,依次类推。

基于前面给出的几个概念,统计1n1的个数的做法是这样的:

  1. 从个位开始遍历n的每一个数位,例如n=322时,依次遍历2,2,3
    • 如果当前数位等于1,则当前数位是1的个数等于upperNum×digitPos+lowerNum+1,即此时1的个数同时由高位upperNum和低位lowerNum确定。例如n=312,对于十位,currNum=1upperNum=3lowerNum=2digitPos=10;此时在十位可能出现1的情况为1019110119210219310312;即为3×10+2+1
    • 如果当前数位小于1,则当前数位是1的个数等于upperNum×digitPos,即此时1的个数仅由upperNum确定。例如n=302,对于十位,currNum=0upperNum=3digitPos=10;此时在十位可能出现1的情况为1019110119,,210219;即为3×10
    • 如果当前数位大于1,则当前数位是1的个数等于(upperNum+1)×digitPos,即此时1的个数仅由upperNum确定。例如n=322,对于十位,currNum=2upperNum=3digitPos=10;此时在十位可能出现1的情况为1019110119210219310319;即为(3+1)×10
    • 有了上面统计1n1的个数的算法,我们很容易验证29也遵循这个规律。0有点小区别,但是也不用太担心,因为对它的求解也是基于上面的大框架。
      统计1n0的个数的做法是这样的:

      1. 从个位开始遍历n的每一个数位。注意最高位不需要处理,可以直接跳过,因为最高位不能为0
      2. 如果当前数位等于0,则当前数位是0的个数等于upperNum1×digitPos+lowerNum+1,即此时0的个数同时由高位upperNum和低位lowerNum确定。例如n=302,对于十位,currNum=0upperNum=3lowerNum=2digitPos=10;此时在十位可能出现0的情况为100109200209300302;即为31×10+2+1

      3. 如果当前数位大于0,则当前数位是0的个数等于upperNum×digitPos,即此时0的个数仅由upperNum确定。例如n=322,对于十位,currNum=2upperNum=3digitPos=10;此时在十位可能出现0的情况为100109200209300309;即为3×10
      4. 容易看出该算法的时间复杂度是O(lgn)
        有了上面统计1n019出现次数的算法,题目的解题思路已经很清晰了,下面给出Java下的实现代码:

        import java.util.Scanner;
        
        public class Main {
        
            public static int countOfNum(int n , int i) {   //1~n中出现数字i的次数
        
                int lowerNum = 0;   //保存低位数字
                int currNum = 0;    //保存当前位
                int upperNum = 0;   //保存高位数字
                int digitPos = 1;   //起始位数是个位   
                int count = 0;  //统计i出现的总次数
        
                while (n / digitPos != 0) {
        
                    lowerNum = n % digitPos;
                    currNum = (n / digitPos) % 10;
                    upperNum = n / (digitPos * 10);
        
                    if (i == 0) {   //i是0时特殊处理
                        if (n / (digitPos * 10) == 0)   //当前位是最高位,则返回
                            break;
                        if (currNum == i)
                            count += (upperNum - 1) * digitPos + lowerNum + 1;
                        else 
                            count += upperNum * digitPos;
                    }
                    else {  //i是1~9时统一处理
                        if  (currNum < i)
                            count += upperNum * digitPos;
                        else if (currNum == i)
                            count += upperNum * digitPos + lowerNum + 1;
                        else 
                            count += (upperNum + 1) * digitPos;
                    }
        
                    digitPos *= 10;
                }
        
                return count;
            }
        
        
            public static void main(String[] args) { 
        
                Scanner in = new Scanner(System.in);
                while(in.hasNext()) {
        
                    int n = in.nextInt();
                    for (int i = 0; i < 10; i++) {
                        int ret = countOfNum(n, i);
                        if (i == 9)
                            System.out.println(ret);
                        else
                            System.out.print(ret + " ");
                    }
                }
            }
        }
        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值