题意:

  给定一个整数n,求1~n这n个整数中十进制表示中1出现的次数。

思路:

  方法1:最直观的是,对于1~n中的每个整数,分别判断n中的1的个数,具体见《剑指offer》。这种方法的时间复杂度为O(N*logN),当N比较大的时候,一般会超时。

  方法2:这种类别的题目,如果直观求解不行的话,那么通常是进行找规律,转化成一个数学问题。这道题目在《编程之美》上有着比较详细的描述,下面就结合一个实例进行具体的分析:

在分析之前,首先需要知道一个规律:

  • 从 1 至 10,在它们的个位数中,数字1出现了 1 次。
  • 从 1 至 100,在它们的十位数中,数字1出现了 10 次。
  • 从 1 至 1000,在它们的百位数中,数字1出现了 100 次。

依此类推,从 1 至 10i,在它们右数第二位中,数字1出现了10 ^ (i - 1)次。

对于 n = 2134,要找到从1 ~ 2134这2134个数字中所有1的个数。我们可以对2134进行逐位分析:

(1)在个位上,从1~2130,包含213个10,因此数字1出现了213次,剩下的数字2131、2132、2133、2134中个位数上只有2131包含树脂字1,剩下的都不包含。所以个位数上的数字1的总数为213 + 1 = 214。

(2)在十位上,从1 ~ 2100,包含了21个100,因此数字1出现了21 * 10 = 210次,剩下的数字从2101 ~ 2134,只有2110 ~ 2119这10个数字中十位的数字为1,所以十位上的数字1的总数为210 + 10 = 220。

(3)在百位上,从1 ~ 2000,包含了2个1000,因此数字1出现了2 * 100 = 200次,剩下的数字从2001 ~ 2134,只有2100 ~ 2134这35个数字中的百位的数字为1,所以百位数上数字1的总数为200 + 35= 235。

(4)在千位上,包含了0个10000,因此数字1出现了0 * 1000 = 0次,剩下的数字中只有1000 ~ 1999这1000个数字中的千位的数字为1,所以千位上的数字1的总数为1000。

因此从1 ~ 2134这n个数字中,数字出现的总的次数为 214 + 220 + 235 +1000 = 1669。

总结一下以上的步骤,可以得到这么一个规律:

对于数字n,计算它的第i(i从1开始,从右边开始计数)位数上包含的数字1的个数:

假设第i位上的数字为x的话,则

1.如果x > 1的话,则第i位数上包含的1的数目为:(高位数字 + 1)* 10 ^ (i-1)  (其中高位数字是从i+1位一直到最高位数构成的数字)

2.如果x < 1的话,则第i位数上包含的1的数目为:(高位数字 )* 10 ^ (i-1)

3.如果x == 1的话,则第i位数上包含1的数目为:(高位数字) * 10 ^ (i-1) +(低位数字+1)   (其中低位数字时从第i - 1位数一直到第1位数构成的数字)

所以,代码如下:

int NumberOfDigitOne(int n) {
if( n < 0)
return 0;
int i = 1;
int high = n;
int cnt = 0;
while(high != 0)
{
high = n / pow(10 ,i);//high表示当前位的高位
int temp = n / pow(10, i - 1);
int cur = temp % 10;//cur表示第i位上的值,从1开始计算
int low = n - temp * pow(10, i - 1);//low表示当前位的低位
if(cur < 1)
{
cnt += high * pow(10, i - 1);
}
else if(cur > 1)
{
cnt += (high + 1) * pow(10 ,i - 1); }
else
{ cnt += high * pow(10, i - 1);
cnt += (low + 1); }
i++;
}
return cnt;
}

该算法的时间复杂度为O(logN)。

===================================================================================================================================
上述算法是计算数字1的个数,对于其他的数字k(1~9中的任意数字),这个规律同样也是适用的,分析的过程也是一样的,只不过将上述的1改为k即可。下面代码是计算1 ~n中任意数字出现的次数:

int NumberOfDigitX(int n, int x) {
if(x > 9 || x < 0 || n < 0)
return 0;
int i = 1;
int high = n;
int cnt = 0;
while(high != 0)
{
high = n / pow(10 ,i);//high表示当前位的高位
int temp = n / pow(10, i - 1);
int cur = temp % 10;//cur表示第i位上的值,从1开始计算
int low = n - temp * pow(10, i - 1);//low表示当前位的低位
if(cur < x)
{
cnt += high * pow(10, i - 1);
}
else if(cur > x)
{
cnt += (high + 1) * pow(10 ,i - 1); }
else
{ cnt += high * pow(10, i - 1);
cnt += (low + 1); }
i++;
}
return cnt;
}

参考:http://www.cnblogs.com/cyjb/p/digitOccurrenceInRegion.html

附:求1~n中数字0的个数

int NumberOfDigitZero(int n) {
if(n < 0)
return 0;
int i = 1;
int high = n;
int cnt = 0;
while(high != 0)
{
high = n / pow(10 ,i);//high表示当前位的高位
int temp = n / pow(10, i - 1);
int cur = temp % 10;//cur表示第i位上的值,从1开始计算
int low = n - temp * pow(10, i - 1);//low表示当前位的低位
if(cur < 0)//实际上这步不会执行
{
cnt += (high - 1) * pow(10, i - 1);
}
else if(cur > 0)
{
cnt += (high) * pow(10 ,i - 1); }
else
{ cnt += (high - 1)* pow(10, i - 1);
cnt += (low + 1); }
i++;
}
return cnt;
}

  

求1~n整数中1出现的次数(《剑指offer》面试题43)的更多相关文章

  1. 剑指offer 面试题43. 1~n整数中1出现的次数

    leetcode上也见过一样的题,当时不会做 看了一下解法是纯数学解法就没看,结果剑指offer上也出现了这道题,那还是认真看下吧 对于数字abcde,如果第一位是1,比如12345,即计算f(123 ...

  2. 剑指offer面试题:输入某二叉树的前序遍历和中序遍历,输出后序遍历

    二叉树的先序,中序,后序如何遍历,不在此多说了.直接看题目描述吧(题目摘自九度oj剑指offer面试题6): 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结 ...

  3. 剑指Offer:面试题15——链表中倒数第k个结点(java实现)

    问题描述 输入一个链表,输出该链表中倒数第k个结点.(尾结点是倒数第一个) 结点定义如下: public class ListNode { int val; ListNode next = null; ...

  4. Leetcode - 剑指offer 面试题29:数组中出现次数超过一半的数字及其变形(腾讯2015秋招 编程题4)

    剑指offer 面试题29:数组中出现次数超过一半的数字 提交网址: http://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163 ...

  5. C++版 - 剑指Offer 面试题45:圆圈中最后剩下的数字(约瑟夫环问题,ZOJ 1088:System Overload类似)题解

    剑指Offer 面试题45:圆圈中最后剩下的数字(约瑟夫环问题) 原书题目:0, 1, - , n-1 这n个数字排成一个圈圈,从数字0开始每次从圆圏里删除第m个数字.求出这个圈圈里剩下的最后一个数字 ...

  6. 【剑指Offer面试题】 九度OJ1517:链表中倒数第k个结点

    鲁棒性是指程序可以推断输入是否符合规范要求,并对不和要求的输入予以 合理的处理. 题目链接地址: http://ac.jobdu.com/problem.php?pid=1517 题目1517:链表中 ...

  7. 【剑指Offer面试题】九度OJ1384:二维数组中的查找

    下决心AC全部剑指offer面试题. 九度OJ面试题地址:http://ac.jobdu.com/hhtproblems.php 书籍:何海涛--<剑指Offer:名企面试官精讲典型编程题> ...

  8. 剑指Offer:面试题32——从1到n整数中1出现的次数(java实现)

    问题描述: 输入一个整数n,求1到n这n个整数的十进制表示中1出现的次数.例如输入12,从1到12这些整数中包含1的数字有1,10,11,12,1一共出现了5次. 思路:(不考虑时间效率的解法,肯定不 ...

  9. 剑指offer面试题3二维数组中的查找

    题目: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 需要与面试官确认的是,这 ...

随机推荐

  1. 20155219 2016-2017-2 《Java程序设计》第8周学习总结

    20155219 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 通用API 日志API 1.java.util.logging包提供了日志功能相关类与接口, ...

  2. HTTP/2及HTTP/3特性

    HTTP/2及HTTP/3特性 摘要: 学习 HTTP/2 与 HTTP/3. 前言 HTTP/2 相比于 HTTP/1,可以说是大幅度提高了网页的性能,只需要升级到该协议就可以减少很多之前需要做的性 ...

  3. Promise-js中的同步和异步

    js中的同步和异步   自从读了研后,走上了学术之路,每天除了看论文就是做实验,最后发现自己还是喜欢开发呀,于是我又重回前端啦~ 隔了这么久没学前端,好像很多东西都忘了不少,而且不得不说前端的技术更新 ...

  4. 10 HashMap,Map.Entry,LinkedHashMap,TreeMap,Hashtable,Collections类

    Map集合的功能概述 添加功能 * V put(K key,V value):添加元素.            * 如果键是第一次存储,就直接存储元素,返回null            * 如果键不 ...

  5. C++ 作业(哈夫曼树)

    #include<bits/stdc++.h> #define fi first #define se second #define int long long using namespa ...

  6. 《DSP using MATLAB》Problem 5.11

    代码: %% ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ %% Output In ...

  7. 数据库连接池——C3P0

    定义: 本质上就是个容器(集合)存放数据库连接的容器.当系统初始化以后,容器被创建,容器中就会申请一些连接对象.当用户来访问的数据库的时候,从容器中取连接对象,用户用完之后归还. 使用方法: 标准接口 ...

  8. 记一次接口504 Gateway Time-out原因及解决方法

    今天在刷新公司项目页面时发现有个板块一直刷新不出数据,最后发现接口报错(504 Gateway Time-out) 通过查看代码发现有个sql语句,如下,特别慢 select `vdc1`,      ...

  9. 数学沉思录:古今数学思想的发展与演变 (Mario Livio 著)

    第1章 神秘的数学 (已看) 发现还是发明 第2章 神秘学:命理学家和哲学家 (已看) 毕达哥拉斯 进入柏拉图的洞穴 第3章 魔法师:大师和异端 (已看) 给我一个支点:我将撬起地球 阿基米德重写稿 ...

  10. WinForm读取指定的config文件的内容

    config文件的使用 一.缘起 最近做项目开始使用C#,因为以前一直使用的是C++,因此面向对象思想方面的知识还是比较全面的,反而是因没有经过完整.系统的.Net方面知识的系统学习,经常被一些在C# ...