文档章节

【九度OJ1373】|【剑指offer32】整数中1出现的次数(从1到n整数中1出现的次数)

aqia358
 aqia358
发布于 2013/10/25 11:20
字数 1946
阅读 239
收藏 1

题目描述:

亲们!!我们的外国友人YZ这几天总是睡不好,初中奥数里有一个题目一直困扰着他,特此他向JOBDU发来求助信,希望亲们能帮帮他。问题是:求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有110111213因此共出现6,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。

输入:

输入有多组数据,每组测试数据为一行。

每一行有两个整数a,b(0<=a,b<=1,000,000,000)

输出:

对应每个测试案例,输出ab之间1出现的次数。

样例输入:
0 5
1 13
21 55
31 99
样例输出:
1
6
4
7
分析:

次题为编程之美上的经典例题从0开始到某个数N有多少个1的变形;

方法一:
遍历0到N的每个数统计每个数中1出现的个数,但是这个算法的致命问题是效率,它的时间复杂度是O(N)*计算一个整数数字里面“1”的个数的复杂度=O(N*logN)

方法二:(参考:http://blog.csdn.net/zcsylj/article/details/6393315)

  仔细分析这个问题,给定了N,似乎就可以通过分析“小于N的数在每一位上可能出现1的次数”之和来得到这个结果。让我们来分析一下对于一个特定的N,如何得到一个规律来分析在每一位上所有出现1的可能性,并求和得到最后的f(N)。

先从一些简单的情况开始观察,看能不能总结出什么规律。

     先看1位数的情况。

      如果N=3,那么从1到3的所有数字:1、2、3,只有个位数字上可能出现1,而且只出现1次,进一步可以发现如果N是个位数,如果N>=1,那么f(N)都等于1,如果N=0,则f(N)为0。

     再看2位数的情况。

     如果N=13,那么从1到13的所有数字:1、2、3、4、5、6、7、8、9、10、11、12、13,个位和十位的数字上都可能有1,我们可以将它们 分开考虑,个位出现1的次数有两次:1和11,十位出现1的次数有4次:10、11、12和13,所以f(N)=2+4=6。要注意的是11这个数在十位和个位都出现了1,但是11恰好在个位为1和十位为1中被计算了两次,所以不用特殊处理,是对的。再 考虑N=23的情况,它和N=13有点不同,十位出现1的次数为10次,从10到19,个位出现1的次数1、11、21,所以f(N)=3+10=13。 通过对两位数进行分析,我们发现,个位出现1的次数不仅和个位数字有关,还和十位数有关:如果N的个位数大于等于1,则个位出现1的次数为十位数的数字加 1;如果N的个位数为0,则个位出现1的次数等于十位数的数字。而十位数字上出现1的次数不仅和十位数有关,还和个位数有关:如果十位数字等于1,则十位 数上出现1的次数为个位数的数字加1;如果十位数大于1,则十位数上出现1的次数为10。

     例如:

            f(13)=个位出现1的个数+十位出现1的个数=2+4=6;

            f(23)=个位出现1的个数+十位出现1的个数=3+10=13;

            f(33)=个位出现1的个数+十位出现1的个数=4+10=14;

              ……

            f(93)=个位出现1的个数+十位出现1的个数=10+10=20;

 

     接着分析3位数。

      如果N=123:

     个位出现1的个数为13:1,11,21,…,91,101,111,121

     十位出现1的个数为20:10~19,110~119

      百位出现1的个数为24:100~123

     f(123)=个位出现1的个数+十位出现1的个数+百位出现1的次数=13+20+24=57;

     同理我们可以再分析4位数、5位数。

    读者朋友们可以写一写,总结一下各种情况有什么不同。

 

     根据上面的一些尝试,下面我们推导出一般情况下,从N得到f(N) 的计算方法:

     假设N=abcde,这里a、b、c、d、e分别是十进制数N的各个位数上的数字。如果要计算百位上出现1的次数,它将会受到三个因素的影响:百位上的数字,百位以下(低位)的数字,百位(更高位)以上的数字。

     如果百位上的数字为0,则可以知道,百位上可能出现1的次数由更高位决定,比如12013,则可以知道百位出现1的情况可能是100~199,1 100~1 199,2 100~2 199,…,11 100~11 199,一共有1200个。也就是由更高位数字(12)决定,并且等于更高位数字(12)*当前位数(100)。

      如果百位上的数字为1,则可以知道,百位上可能出现1的次数不仅受更高位影响,还受低位影响,也就是由更高位和低位共同决定。例如对于12113,受更高位影响,百位出现1的情况是100~199,1 100~1 199,2 100~2 199,…,11 100~11 199,一共有1200个,和上面第一种情况一样,等于更高位数字(12)*当前位数(100)。它还受低位影响,百位出现1的情况是12 100~12 113,一共114个,等于低位数字(113)+1。

     如果百位上数字大于1(即为2~9),则百位上可能出现1的次数也仅由更高位决定,比如12 213,则百位出现1的可能性为100~199,1 100~1 199,2 100~2 199,…,11 100~11 199,12 100~12 199,一共有1300个,并且等于更高位数字+1(12+1)*当前位数(100)。

      通过上面的归纳和总结,我们可以写出如下的更高效算法来计算f(N):

   ‍其算法思路是:通过对数字进行有规律的总结,发现从1到N,中出现的所有的1的总数。可以从N这个数总结出来的。

      那么出现1的总数应该等于,个位上出现1的次数+十位上出现1的次数+百位上出现1的次数+。。。。。。

     所以对于一个数abcde,取百位上的c来计算,

              假若c是"1",那么百位上1的个数是由他的高位和低位来决定的。等于ab*100+cde+1;

              假若c是"0",那么百位上1的个数是ab*100;

               假如c是大于1,那么 百位上1的个数是(ab+1)*100;

Java实现:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;

public class Main {

	public static int sum(int n){
		if(n < 1)return 0;
		int count = 0;
		int Factor = 1;
		int LowerNum = 0;
		int CurrNum = 0;
		int HigherNum = 0;
		while(n/Factor != 0){
			LowerNum = n - (int)Math.floor(n/Factor)*Factor;
			CurrNum = (n/Factor)%10;
			HigherNum = n/(Factor*10);
			switch(CurrNum){
				case 0:
					count += HigherNum*Factor;
					break;
				case 1:
					count += HigherNum*Factor + LowerNum + 1;
					break;
				default:
					count += (HigherNum + 1) * Factor;
					break;
			}
			Factor *= 10;
		}
		return count;
	}
	public static void main(String[] args) throws IOException {
		StreamTokenizer st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
		while(st.nextToken() != StreamTokenizer.TT_EOF){
			int a = (int) st.nval;
			st.nextToken();
			int b = (int) st.nval;
			if(a < b)
				System.out.println(sum(b) - sum(a-1));
			else
				System.out.println(sum(a) - sum(b-1));
		}
		
	}

}






© 著作权归作者所有

共有 人打赏支持
aqia358
粉丝 6
博文 82
码字总数 30297
作品 0
海淀
程序员
那些算频率的算法,现在都怎么样了?

面试 19:输出数组中出现次数超过一半的数字(剑指 Offer 26 题) 上一篇推文给大家留下的习题来自于《剑指 Offer》第 29 题:数组中超过一半的数字,不知道各位去思考了么? 面试题:数组中...

南尘
08/02
0
0
面试 19:输出数组中出现次数超过一半的数字(剑指 Offer 26 题)

面试 19:输出数组中出现次数超过一半的数字(剑指 Offer 26 题) 上一篇推文给大家留下的习题来自于《剑指 Offer》第 29 题:数组中超过一半的数字,不知道各位去思考了么? 面试题:数组中...

nanchen2251
08/02
0
0
[剑指offer] 整数中1出现的次数(从1到n整数中1出现的次数)

本文首发于我的个人博客:尾尾部落 题目描述 求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对...

繁著
07/13
0
0
海量数据处理之面试题

给定a、b两个文件,各存放50亿个url,每个url各占64字节,内存限制是4G,让你找出a、b文件共同的url? 方案1:可以估计每个文件安的大小为50G×64=320G,远远大于内存限制的4G。所以不可能将...

huangqjduter
2017/03/02
0
0
python剑指offer66题

二维数组的查找 替换空格 从头到尾打印链表 重建二叉树 用两个栈实现队列 选择数组中的最小数字 斐波那契数列 跳台阶 变态跳台阶 矩形覆盖 二进制中1的个数 数值的整数次方 调整数组顺序使奇...

lyy0905
06/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

InvalidKeyException: Illegal key size

Caused by: java.lang.RuntimeException: java.security.InvalidKeyException: Illegal key size 解决方案:去官方下载JCE无限制权限策略文件。 jdk 5: http://www.oracle.com/technetwork/j......

自由的开源
8分钟前
0
0
JAVA秒杀实现以及优化原理

秒杀与其他业务最大的区别在于:秒杀的瞬间, (1)系统的并发量会非常的大 (2)并发量大的同时,网络的流量也会瞬间变大。 关于(2),最常用的办法就是做页面静态化,也就是常说的前后端分...

小贱是个程序员
12分钟前
1
0
Spring Aop之Advisor解析

在上文Spring Aop之Target Source详解中,我们讲解了Spring是如何通过封装Target Source来达到对最终获取的目标bean进行封装的目的。其中我们讲解到,Spring Aop对目标bean进行代理是通过Ann...

爱宝贝丶
14分钟前
0
0
Java高级工程师面试阿里,阿里云,天猫,菜鸟,涉及到的知识点

前言: 分享 Java高级工程师面试阿里,阿里云,天猫,菜鸟,涉及到的知识点,文章有点长,但比较全面,阅读时间15分钟左右,干货满满。 一、HashMap的那些事 1.1、HashMap的实现原理 1.1.1、...

Java大蜗牛
39分钟前
2
0
nginx模块学习五 expires 浏览器缓存

缓存原理 语法 Syntax: expires [modified] time;expires epoch | max | off;Default: expires off;Context: http,server,location,if in location 例/etc/nginx/conf.d/default.con......

Romanceling
50分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部