文档章节

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

aqia358
 aqia358
发布于 2013/10/25 11:20
字数 1946
阅读 255
收藏 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
海淀
程序员
私信 提问
剑指offer 31. 整数中1出现的次数(从1到n整数中1出现的次数)

原题 题目: 求出1 ~ 13的整数中1出现的次数,并算出 100 ~ 1300的整数中1出现的次数?为此他特别数了一下1 ~ 13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。...

dby_freedom
11/14
0
0
面试 19:输出数组中出现次数超过一半的数字(剑指 Offer 26 题)

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

nanchen2251
08/02
0
0
那些算频率的算法,现在都怎么样了?

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

南尘
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
[算法总结] 13 道题搞定 BAT 面试——字符串

本文首发于我的个人博客:尾尾部落 1. KMP 算法 谈到字符串问题,不得不提的就是 KMP 算法,它是用来解决字符串查找的问题,可以在一个字符串(S)中查找一个子串(W)出现的位置。KMP 算法把...

繁著
09/05
0
0

没有更多内容

加载失败,请刷新页面

加载更多

RestClientUtil和ConfigRestClientUtil区别说明

RestClientUtil directly executes the DSL defined in the code. ConfigRestClientUtil gets the DSL defined in the configuration file by the DSL name and executes it. RestClientUtil......

bboss
40分钟前
6
0

中国龙-扬科
昨天
2
0
Linux系统设置全局的默认网络代理

更改全局配置文件/etc/profile all_proxy="all_proxy=socks://rahowviahva.ml:80/"ftp_proxy="ftp_proxy=http://rahowviahva.ml:80/"http_proxy="http_proxy=http://rahowviahva.ml:80/"......

临江仙卜算子
昨天
8
0
java框架学习日志-6(bean作用域和自动装配)

本章补充bean的作用域和自动装配 bean作用域 之前提到可以用scope来设置单例模式 <bean id="type" class="cn.dota2.tpye.Type" scope="singleton"></bean> 除此之外还有几种用法 singleton:......

白话
昨天
8
0
在PC上测试移动端网站和模拟手机浏览器的5大方法

总结很全面,保存下来以备不时之需。原文地址:https://www.cnblogs.com/coolfeng/p/4708942.html

kitty1116
昨天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部