剑指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 }

原文地址:https://www.cnblogs.com/pathjh/p/9374772.html

时间: 2024-10-12 07:39:45

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

《剑指offer》第四十三题(从1到n整数中1出现的次数)

// 面试题43:从1到n整数中1出现的次数 // 题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数.例如 // 输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次. #include <iostream> #include <cstring> #include <cstdlib> // ====================方法一==================== //逐个判断,时间复杂度为O(nlogn)

《剑指offer》第四十三题:从1到n整数中1出现的次数

// 面试题43:从1到n整数中1出现的次数 // 题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数.例如 // 输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次. #include <cstdio> #include <cstring> #include <cstdlib> // ====================方法一==================== // 笨方法, 时间复杂度O(nlogn) i

剑指Offer面试题11(Java版):数值的整数次方

题目:实现函数double Power(double base,int exponent),求base的exponent次方.不得使用库函数,同时不需要考虑大数问题 1.自以为很简单的解法: 由于不需要考虑大数问题,这道题看起来很简单,可能不少应聘者在看到题目30秒后就能写出如下的代码: public double powerWithExponent(double base,int exponent){ double result = 1.0; for(int i = 1;i<= exponen

【剑指Offer学习】【面试题38:数字在排序数组中出现的次数】

题目:统计一个数字:在排序数组中出现的次数. 举例说明 例如输入排序数组{ 1, 2, 3, 3, 3, 3, 4, 5}和数字3 ,由于3 在这个数组中出现了4 次,因此输出4 . 解题思路 利用改进的二分算法. 如何用二分查找算法在数组中找到第一个k,二分查找算法总是先拿数组中间的数字和k作比较.如果中间的数字比k大,那么k只有可能出现在数组的前半段,下一轮我们只在数组的前半段查找就可以了.如果中间的数字比k小,那么k只有可能出现在数组的后半段,下一轮我们只在数组的后半乓查找就可以了.如果中

《剑指offer》第六十三题(把字符串转换成整数)

// 面试题67:把字符串转换成整数 // 题目:请你写一个函数StrToInt,实现把字符串转换成整数这个功能.当然,不 // 能使用atoi或者其他类似的库函数. #include <iostream> long long StrToIntCore(const char* str, bool minus); enum Status { kValid = 0, kInvalid }; int g_nStatus = kValid;//设置全局错误变量,用来反映无效输入 int StrToIn

[剑指offer] 重建二叉树,根据前中,输出后,根据中后,输出前

参考:<剑指offer>纪念版 情况1.:给出树的前序序列和中序序列,输出后序序列 情况2 :给出树的后序序列和中序序列,输出前序序列 解决方法:根据所给出的两个序列,构造出(重建)二叉树,然后按要求再遍历输出. 重建二叉树主要利用了递归的思想,最重要的是找出序列的范围(函数传参),这个要非常仔细,很容易出错.一定要在纸上画出图,然后根据图来确定范围. 用到的两个函数: 以情况1为例: 主要用到了两个函数: BinaryTreeNode* Construct(char* preorder, c

【Java】 剑指offer(39) 数组中出现次数超过一半的数字

本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1, 2, 3, 2, 2, 2, 5, 4, 2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2. 思路 思路一:数字次数超过一半,则说明:排序之后数组中间的数字一定就是所求的数字. 利用partition()函数获得某一随机数字,其余数字按大小排在该数字的左右.若该

【Java】 剑指offer(51)数组中的逆序对

本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 思路 如果遍历数组,对每个数字都和后面的数字比较大小,时间复杂度为O(n^2),效率太低. 利用归并排序的思想,先将数组分解成为n个长度为1的子数组,然后进行两两合并同时排好顺序. 在对两个子区域合并排序时,记左边区域(下标为start~mid)的指针

【剑指Offer学习】【所有面试题汇总】

剑指Offer学习 剑指Offer这本书已经学习完了,从中也学习到了不少的东西,现在做一个总的目录,供自已和大家一起参考,学如逆水行舟,不进则退.只有不断地学习才能跟上时候,跟得上技术的潮流! 所有代码下载[https://github.com/Wang-Jun-Chao/coding-interviews] 目录 第01-10题 [剑指Offer学习][面试题02:实现Singleton 模式--七种实现方式] [剑指Offer学习][面试题03:二维数组中的查找] [剑指Offer学习][面

【剑指offer】整数中1出现的次数

转载请注明出处:http://blog.csdn.net/ns_code/article/details/27563485 题目描写叙述: 亲们!! 我们的外国友人YZ这几天总是睡不好,初中奥数里有一个题目一直困扰着他,特此他向JOBDU发来求助信,希望亲们能帮帮他.问题是:求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包括1的数字有1.10.11.12.13因此共出现6次,可是对于后面问题他就没辙了.ACMer希望你们帮帮他,并把问题