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 }
  • 相关阅读:
    Martix工作室考核题 —— 打印一个菱形
    Martix工作室考核题 —— 打印一个菱形
    Martix工作室考核题 —— 打印九九乘法表
    Martix工作室考核题 —— 打印九九乘法表
    Martix工作室考核题 —— 打印九九乘法表
    Martix工作室考核题 —— 201938 第三题
    Martix工作室考核题 —— 201938 第三题
    Martix工作室考核题 —— 201938 第三题
    Martix工作室考核题 —— 201938 第一题
    fiddler模拟发送post请求
  • 原文地址:https://www.cnblogs.com/pathjh/p/9374772.html
Copyright © 2011-2022 走看看