剑指offer 计算1到n中所有1出现的次数

    

     如题,显而易见,我们可以依次计算所有数中的1来完成该功能:

int NumOfOneBetweenN(int n)
{
    int sum = 0;
    for(int i=1;i<n;++i)
        sum += NumOfOne(i);
    return sum;
}

int NumOfOne(int i)
{
    int sumi = 0;
    while(i)
    {
        if(i%10 == 1)
            sumi++;
        i/=10;
    }
    return sumi;
}

      时间复杂度为O(n*logn),效率不高。

      那么,换一种思路考虑,计算每个位出现1的次数,当然,要先找到数学规律,这需要归纳推理:

      设输入数字为n,1出现的次数为t,每一位出现的次数为ti.

      n为个位数: 显而易见,  n>=1,t=1;

                  n=0,t=0

n为十位数: n=13,个位出现1的情况:1,11, 十位出现1的情况:10,11,12,13       t=2+4=6;

n=23,个位出现1的情况:1,11,21, 十位出现1的情况:10~19        t=3+10=13;

              n=33,个位出现1的情况:1,11,21,31, 十位出现1的情况: 10~19  t=4+10=14;

            我们发现,当十位数>1,十位出现的次数固定: t10=10;

               十位数=1,次数由个位大小决定: t10=t1+1;

               个位数>1,次数由十位大小决定: t1=t10+1.

       n为三位数: n=123,个位出现1的情况:1~91,101~121, 十位数出现1的情况: 10~19,110~119 , 百位出现1的情况: 100~123   t=13+20+24=57;

            n=223,个位出现1的情况:1~91,101~191,201~221, 十位出现1的情况: 10~19,110~119,210~219, 百位出现1的情况: 100~199 t=23+30+100=153;

            我们发现,十位的次数被高位影响,个位的次数也被高位影响,而百位和上面十位>1的情况一样,次数固定,=1的情况又会被低位影响

            不妨,我们可以设一个五位数,我们要计算百位出现1的次数,那么可以把数字分成三部分,百位之前的高位,百位,百位之后的低位.

            1.百位=0,百位出现1的次数只与高位有关.比如12013,百位出现1的情况:00100~00199,01100~01199...11100~11199.共1200个,也就是高位*本位固定后的次数,即12*100;

            2.百位>1,百位出现1的次数只与高位有关.比如12313,百位出现1的情况,00100~00199,01100~01199...12100~12199,共1300个,也就是(高位+1)*1本位固定后的次数,即13*100;

            3.百位=1,百位出现1的次数与高低位都有关.比如12113,百位出现1的情况,00100~00199...11100~11100,还有12100~12113,共1314个,也就是高位*本位固定后的次数+低位+1,即12*100+114

            归纳: 某一位=0的时候,该位出现1的次数被高位决定,即 0该位~(高位-1)该位,共高位*该位固定数;

              某一位>1的时候,该位出现1的次数被高位决定,即 0该位~高位该位,共(高位+1)*该位固定数;

             某一位=1的时候,该位出现1的次数被高低位决定,即 0该位~(高位-1)该位 , 该位0~该位低位,共高位*该位固定数+低位+1;

           本质上,其实只有两种情况: 1.ti=0||ti>1,可以被高位按固定次数列举完

                         2.ti=1,被高位按固定次数列举完之后,还有不足固定次数的,由低位决定

int NumOfOneBetweenN(int n)
{
    int count = 0;
    int i = 1;
    int cur = 0,after = 0,before = 0;

    //循环处理每一位
    while((n/i)!=0)
    {
        cur = (n/i)%10;
        before = n/(i*10);
        after = n - (n/i)*i;

        if(cur>1)
            count += (before+1)*i;
        else if(cur==0)
            count += before*i;
        else
            count += before*i + after + 1;

        i*=10;
    }
    return count;
}

  

          

              

              

原文地址:https://www.cnblogs.com/Duikerdd/p/12179314.html

时间: 2024-08-10 05:36:25

剑指offer 计算1到n中所有1出现的次数的相关文章

【剑指offer】二维数组中的查找

题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 分析: 首先选择数组中右上角的数字.如果该数字等于要查找的数字,查找过程结束:如果该数字大于要查找的数字,剔除这个数字所在的列:如果该数字小于要查找的数字,剔除这个数字所在的行.依次类推,直到查找范围为空. 示例程序: #include <stdio.h> #include <stdlib.h> int

【剑指offer】Q29:数组中出现次数超过一半的数字

就本题而言,个人觉得练习下partition函数是有必要的,毕竟它是快速排序的核心,是基础性的东西,也是必须要掌握的,至于书中给出的"取巧"性解法,是属于个人思维能力的考察,是一种考虑问题的思路,不是一两个问题就能练就的. partition函数,包括快速排序,是一定要信手拈来的,必须的. import random def MoreThanHalf(array): if len(array) == 0: return 0 start = 0 end = len(array) - 1

剑指OFFER之二维数组中的查找(九度OJ1384)

题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 输入: 输入可能包含多个测试样例,对于每个测试案例, 输入的第一行为两个整数m和n(1<=m,n<=1000):代表将要输入的矩阵的行数和列数. 输入的第二行包括一个整数t(1<=t<=1000000):代表要查找的数字. 接下来的m行,每行有n个数,代表题目所给出的m行n列的矩阵(矩阵如题目描述所示,每

【剑指offer】Q40:数组中出现一次的数字

按着书里面讲述的方法,根据某一位来将整个数组拆分成两个部分,取每一部分中出现一次的数.书中的处理略显复杂,这里简化下分类的方法. def once(array): reOR = 0 for x in array: reOR ^= x bit1 = firstBit1(reOR) first = 0 second = 0 for x in array: if x & bit1 != 0: first ^= x else: second ^= x return first, second def f

【剑指offer】Q40:数组中出现一次的数

书里面关于分类的判断有些麻烦,通过某一位为0为1来对数组元素进行分类.假如第3位为1,那么也就是元素x & 8 等于或不等于0,所以没必要非的用第几位去判断. def once(array): reOR = 0 for x in array: reOR ^= x bit1 = firstBit1(reOR) first = 0 second = 0 for x in array: if x & bit1 != 0: first ^= x else: second ^= x return f

《剑指Offer 1.二维数组中的查找》2019-03-25

剑指Offer  第一题 题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 本人简单的解题思路  就是通过二重循环,遍历.查找数组中是否有目标数字,思路是简单的,但是有个小坑 ,就是没有进行数组越界判断 少判断了  array = [ [ ] ] 这种情况,最终通过的代码为 public class Solution { public bool

[剑指Offer]5.二维数组中的查找

题目 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 思路 [算法系列之三十三]杨氏矩阵 代码 /*--------------------------------------- * 日期:2015-07-19 * 作者:SJF0115 * 题目: 5.二维数组中的查找 * 网址:http://www.nowcoder.com/books/coding-interviews/a

【剑指offer】18.删除链表中重复节点

思路 实现 /* 说下大概思路: 与链表的其他题目类似,为了防止删除头结点的极端情况发生,先创建空结点dummy,使dummy指向传入的head结点. 然后创建cur的指针,指向链表的头部(即dummy). 接着对cur指针迭代,因为要对比cur(cur最初始的定义指向空结点)指针的下一个结点与下下一个结点的值是否相等,为了防止产生空指针异常,故退出迭代的条件为:cur.next != null && cur.next.next != null. 在迭代过程中,如果cur.next.val

剑指offer:在排序数组中查找数字

题目: 统计一个数字在排序数组中出现的次数. 例如输入排序数组{1,2,3,3,3,3,4,5},由于3在这个数中出现了4次,输出4. # -*- coding: utf-8 -*- # @Time : 2019-07-13 15:10 # @Author : Jayce Wong # @ProjectName : job # @FileName : getNumberOfK.py # @Blog : https://blog.51cto.com/jayce1111 # @Github : ht