zoukankan      html  css  js  c++  java
  • 剑指offer-整数中1出现的次数(从1到n整数中1出现的次数)

    题目:整数中1出现的次数(从1到n整数中1出现的次数)

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

    思路分析

    方法一:统计1-n之间1出现的次数,首先我们可以采用暴力解法直接数,从n到1,对于每个数都进行判断,如果含有1,则计数器加一。判断的方法是将每个数当成字符串,对于字符串的每一位是否为1进行判断即可.。

    实现代码:

     1 public class Solution {
     2     public int NumberOf1Between1AndN_Solution(int n) {
     3         int count=0;
     4         while(n>0){
     5             String str=String.valueOf(n);
     6             char [] chars=str.toCharArray();
     7             for(int i=0;i<chars.length;i++){
     8                 if(chars[i]=='1')
     9                     count++;
    10             }
    11             n--;
    12         }
    13         return count;
    14     }
    15 }

    现在来分析一下上面代码的时间复杂度,总的外循环是从n到1,循环了n次,而内部的循环与n的位数有关。所以总的循环判断次数=(9)*1+(99-10+1)*2+(999-100+1)*3+(9999-1000+1)*4+...

    总的时间复杂度是比较接近O(n)线性的,但是要大于O(N)

    方法二:仔细观察也是可以找到规律的。

    以n=12345为例子,12345=10000+2000+300+40+5,12345可以从每一位上单独进行分析,我们以i表示位数标识,以百位为例

    i=100  此时a=12345/100=123 ,  b=12345%100=45  可以拆成前后两部分的,对于两部分可以先分开计算然后最后再相乘或相加(计数原理)

    1. 如果百位上的数字大于等于2(此时为3),则前面部分共可以出现123/10+1次,即(00~12)共能出现13次1,而每个1又重复了100次(如00100~00199,01100~01199,12100~12199等, ) 故总的次数=(a/10+1)*100
    2. 如果百位上的数字等于1,如n=23145,此时a=231,b=45  此时对于前面部分共可以出现a/10+1(00~23)共24次1,但是此时只有前23个能重复100次,最后一个23100~23145只能有46次,这就与前一种情况不同,所以总的次数=a/10*100+(b+1)
    3. 如果百位上的数字等于0,如n=12045 ,此时a=120 ,b=45,此时对于前面的部分共可以出现a/10(00~11)共12次1,这12个1能重复100,后面的已经没有百位上的1出现了,所以总的次数=a/10*100

    由于每一位上的情况都可以与百位上的情况相同,所以我们可以对以上规律进行总结归纳

    如果百位上的数字大于等于2或是等于0,那么出现1的次数=(a+8)/10*100

    (为什么加8,我们从上面可以看出大于等于2会比等于0在前面多出现一次1,为了得到对应的结果我们直接让大于等于2的向前进位后再取整,而等于0的由于其没有什么进位所以不会影响其结果)(如果题目由此变形一下,求2出现的次数,那么同理我们便可以划分为大于等于3的情况,等于2的情况,小于2的情况,此时可能就要加7)

    如果百位上的数字等于1,那么总的次数由两部分组成,次数=a/10*100+(b+1)

    让i从1开始逐步变为10,100,1000,。。。便可求出各个位上的1的数目,在循环的同时求和就行

    代码如下:

     1 public class Solution {
     2     public int NumberOf1Between1AndN_Solution(int n) {
     3         long count=0;
     4         long i=1;
     5         for(i=1;i<=n;i*=10){
     6             long a=n/i,b=n%i;
     7             count=count+(a+8)/10*i+(a%10==1?1:0)*(b+1);
     8         }
     9        return (int)count;     
    10     }
    11 }
  • 相关阅读:
    高通平台msm8953 Linux DTS(Device Tree Source)设备树详解之二(DTS设备树匹配过程)
    Linux DTS(Device Tree Source)设备树详解之一(背景基础知识篇)
    ACPI Table 与 Device Tree
    Electron 的 安装
    adb连接安卓设备失败failed to start daemon
    Linux greybus
    Android安卓版本、API级别和Linux内核对应关系
    「转」Android编译选项中的eng、user、user-debug
    高通SOC启动流程
    Android for MSM Project
  • 原文地址:https://www.cnblogs.com/pathjh/p/9374772.html
Copyright © 2011-2022 走看看