• 整数中1出现的次数


    题目描述

    求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

    思路一

    依次统计1-n每个数中1的个数,然后依次累加得到最后1出现的总次数

     public int NumberOf1ToI(int i){
            int countOfI = 0;
            while(i > 0){//注意这里不能等于0,否则就是一个死循环了,0/10永远等于0
                int rem = i % 10;            
                if(rem == 1) countOfI++;
                i = i / 10;
            }
            return countOfI;
        }
        
        public int NumberOf1Between1AndN_Solution(int n) {
            int count = 0;
            for(int i = 1; i <= n; i++){
                count += NumberOf1ToI(i);
            }
        
            return count;
        }
    

    时间复杂度:

    对于数字n有o(lgn)位,而我们需要判断每一位数字是不是1

    从1-n那么总共的时间复杂度就是o(nlogn)

    思路二

    举例发现其中的规律

    • n为一位数:n ={1,2,3…9};1出现的次数只能为1

    • n为两位数:

      • n =13 ;那么1出现的次数 = 个位出现1 + 十位出现1 ={1,11}+{10,11,12,13} = 2 + 4 = 6=2+(3+1)=>当十位数字<1时,次数和个位数字的大小有关
      • n = 15;1出现的次数 = 个位出现1 + 十位出现1={1,11}+{10,11,12,13,14,15}=2+6=8=2+(5+1)=>(3+1)=>当十位数字<1时,次数和个位数字的大小有关
      • n=23;1出现的次数=个位出现1 + 十位出现1={1,11,21}+{10,11,12,13,4,15,16,17,18,19}=3 + 10 = 13 = (2+1) +10=>当十位数字>1时,次数和十位数字的大小有关
      • n = 45;1出现的次数=个位出现1 + 十位出现1={1,11,21,31,41}+{10,11,12,13,4,15,16,17,18,19}=5+10=15=(4+1)+10=>当十位数字>1时,次数和十位数字的大小有关
    • n为三位数:

      • n=123;1出现的次数 = 个位出现1 + 十位出现1 +百位出现1={1,11,21,31,41,51,61,71,81,91,101,111,121}+{10-19,110-119}+{100-123}=13+20+24=57

    总结规律:

    假设N = abcde(a,b,c,d,e分别代表个位,十位,百位。。。上的数字)

    那么同样根据上面的推理:

    1出现的次数 = 个位出现1的次数 + 十位出现1 的次数+百位出现1的次数+千位出现1的次数+万位出现1的次数

    这里以百位出现1的次数为例:

    • c = 0: 百位出现1的次数 = highNumber * 100 =ab * 100
    • c = 1: 百位出现1的次数=highNumber * 100 + lowNumber+1
    • c>1: 百位出现1的次数=(highNumber+1) * 100

    举例:

    • c=0: N = 12013 百位出现1的次数 = {100-199,1100-1199,2100-2199,3100-3199,。。。9100-999,10100-10199, 11100-11199}=12 * 100 =1200 = highNumber * 100

    • c=1:N=12113 百位出现1的次数= {100-199,1100-1199,2100-2199,3100-3199,。。。9100-999,10100-10199, 11100-11199} + {12100-12113} = {N = 12013时百位出现1的次数} + {12100-12113 } = 1200 + 114 = 12 * 100 + 113 +1 = highNumber * 100 + lowNumber+1

    • c>1:N=12213 百位出现1的次数= {100-199,1100-1199,2100-2199,3100-3199,。。。9100-999,10100-10199, 11100-11199,12100-12199} = 13 * 100 = (12 + 1) * 100 = (highNumber+1) * 100

    时间复杂度:o(logn)

    public int NumberOf1Between1AndN_Solution(int n) {
            int count = 0;//1的个数
            int i = 1;//轮询代表(个位->十位->百位->千位。。。。)
            int current = 0,lowNumber = 0,highNumber = 0;
           //注意终止条件
            while((n/i)!= 0){
                current = (n/i)%10; //当前位数字
                System.out.println("当前位current:"+current);
                highNumber = n/(i*10); //高位数字
                System.out.println("高位数字highNumber:"+highNumber);
                //注意低位如何表示
                lowNumber = n-(n/i)*i; //低位数字
                System.out.println("低位数字lowNumber:"+lowNumber);
    
                //如果为0,出现1的次数由高位决定,等于高位数字 * 当前位数
                if (current == 0)
                    count += highNumber*i;
                    //如果为1,出现1的次数由高位和低位决定,高位*当前位+低位+1
                else if(current == 1)
                    count += highNumber * i + lowNumber + 1;
                    //如果大于1,出现1的次数由高位决定,//(高位数字+1)* 当前位数
                else{
                    count += (highNumber + 1) * i;
                }
                //前移一位
                i = i*10;
            }
            return count;
        }
    
    
    
    
    21345
    当前位current:5
    高位数字highNumber:2134
    低位数字lowNumber:0
    当前位current:4
    高位数字highNumber:213
    低位数字lowNumber:5
    当前位current:3
    高位数字highNumber:21
    低位数字lowNumber:45
    当前位current:1
    高位数字highNumber:2
    低位数字lowNumber:345
    当前位current:2
    高位数字highNumber:0
    低位数字lowNumber:1345
    18821
    
    
    

    参考

    剑指offer-整数中1出现的次数(从1到n整数中1出现的次数)

    [剑指offer三十一之连数中1出现的次数(从1到n整数中1出现的次数]

    [[剑指offer] 整数中1出现的次数(从1到n整数中1出现的次数)]

    从0开始到某个数N有点多少个1——编程之美2.4

  • 相关阅读:
    linux上搭建私人Git服务器的详细教程
    25个经典的Spring面试问答
    面试题汇总
    idea 中添加查看字节码工具
    HTTP 及 http 请求解析过程
    常见的攻击类型及防范
    Postman 压力测试
    Postman 接口测试配置 Pre-request Script
    jq图片展示插件highslide.js
    cesium transform 倾斜摄影模型矩阵指定经纬度
  • 原文地址:https://www.cnblogs.com/flyingcr/p/10698551.html
Copyright © 2020-2023  润新知