剑指offer:整数中1出现的次数(从1到n整数中1出现的次数)

参考: https://troywu0.gitbooks.io/interview/整数中出现1的次数(从1到n整数中1出现的次数).html

题目描述

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

解题思路1 (暴力法,时间复杂度: O(nlog(n))

 1 public int NumberOf1Between1AndN_Solution(int n) {
 2     int count = 0;
 3     while (n > 0) {
 4         String nStr = String.valueOf(n);
 5         for (int i = 0; i < nStr.length(); i++) {
 6             if (nStr.charAt(i) == ‘1‘)
 7                 count++;
 8         }
 9         n--;
10     }
11     return count;
12 }

这种方法的思路简单,统计每一个数中出现1的次数,能够快速写出代码。但是,这种方法的时间复杂度很高,O(nlog(n)),面试这么写,估计不会留下好的印象。

解题思路2 (数学规律法,时间复杂度: O(log(n))

 1 public int NumberOf1Between1AndN_Solution(int n) {
 2     int low = 0, cur = 0, high = 0;
 3     int count = 0;
 4     int factor = 1;
 5     while (factor <= n) {
 6         high = n / (factor * 10);
 7         low = n % factor;
 8 //            cur = (n - high * (factor * 10) - low) / factor;
 9         cur = (n / factor) % 10;
10         if (cur == 0)
11             count += high * factor;
12         else if (cur == 1)
13             count += high * factor + low + 1;
14         else
15             count += (high + 1) * factor;
16         factor *= 10;
17     }
18     return count;
19 }

这一个思路利用了数字的规律和特点,解决问题的效率非常的高,时间复杂度只与数的位数有关。

首先看一个规律:

  • 从1 - 10中,个位中 1 出现的次数是1,即1这个数;
  • 从1 - 100中,十位中 1 出现的次数是10, 即10, 11, ..., 18, 19;
  • 从1 - 1000中,百位中 1 出现的次数是100,即100, 101, ..., 198, 199;
  • 以此类推。

假设有一个四位数,使用 cur 来表示当前位数对应的数值,high表述cur左边的数,low表示cur右边的数。会有三种情况产生:

  • 第一种:cur = 0,1出现的次数等于 high * (该位数对应的基数)

    • 假设四位数为1023,求百位上1出现的次数;
    • 此时 high = 1, cur = 0, low = 23;
    • 次数 = 1 * 100;
    • 即100, 101, ..., 198, 199。
  • 第二种:cur = 1,1出现的次数等于 high * (该位数对应的基数) + low + 1

    • 假设四位数为1123,求百位上1出现的次数;
    • 此时 high = 1, cur = 1, low = 23;
    • 次数 = 1 * 100 + 23 + 1;
    • 即100, 101, ..., 198, 199  +  1100, 1101, ..., 1122, 1123。
  • 第三种:cur > 1,1出现的次数等于 (high + 1) * (该位数对应的基数)
    • 假设四位数为1223,求百位上1出现的次数;
    • 此时 high = 1, cur = 2, low = 23;
    • 次数 = (1 + 1) * 100;
    • 即100, 101, ..., 198, 199  + 1100, 1101, ..., 1198, 1199。

根据这一规律,从最低位至最高位,依次求出1出现的次数,最后相加得到最终的结果。

原文地址:https://www.cnblogs.com/xiaoyebula/p/12031581.html

时间: 2024-11-05 23:34:56

剑指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希望你们帮帮他,并把问题