【九度OJ1373】|【剑指offer32】整数中1出现的次数(从1到n整数中1出现的次数)
来源:互联网 发布:mac如何恢复苹果系统 编辑:程序博客网 时间:2024/05/18 03:50
【九度OJ1373】|【剑指offer32】整数中1出现的次数(从1到n整数中1出现的次数)
aqia358 发布于 2年前,共有 0 条评论
题目描述:
亲们!!我们的外国友人YZ这几天总是睡不好,初中奥数里有一个题目一直困扰着他,特此他向JOBDU发来求助信,希望亲们能帮帮他。问题是:求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。
输入:输入有多组数据,每组测试数据为一行。
每一行有两个整数a,b(0<=a,b<=1,000,000,000)。
输出:对应每个测试案例,输出a和b之间1出现的次数。
样例输入:0 51 1321 5531 99样例输出:
1647分析:
次题为编程之美上的经典例题从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。这里应该是13+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;不应该是cde吧,应该是de
假若c是"0",那么百位上1的个数是ab*100;
假如c是大于1,那么 百位上1的个数是(ab+1)*100;
复杂度高的方法:
/*N = abcde 百位上数字是c 仅以求百位上出现1的情况为例。 */ int count = 0; //百位上数字为0,百位上可能出现1的次数由更高位决定 if(c == 0){ //等于更高位数字(ab)* 当前位数(100) count += ab*100; } //百位上数字为1,百位上可能出现1的次数不仅受更高位影响还受低位影响 else if(c == 1){ //更高位数字(ab) * 当前位数(100) + 低位数字(de)+1 count += ab*100 + de + 1; } //百位上数字大于1(2~9),百位上出现1的情况仅由更高位决定 else{ //(更高位数字+1(ab+1))* 当前位数(100) count += (ab + 1) * 100; }
本文所说的方法:
#include<stdio.h> long long int Count(long long int n){ //1的个数 long long int count = 0; //当前位 long long int Factor = 1; //低位数字 long long int LowerNum = 0; //当前位数字 long long int CurrNum = 0; //高位数字 long long int HigherNum = 0; if(n <= 0){ return 0; } while(n / Factor != 0){ //低位数字 LowerNum = n - (n / Factor) * Factor; //当前位数字 CurrNum = (n / Factor) % 10; //高位数字 HigherNum = n / (Factor * 10); //如果为0,出现1的次数由高位决定 if(CurrNum == 0){ //等于高位数字 * 当前位数 count += HigherNum * Factor; } //如果为1,出现1的次数由高位和低位决定 else if(CurrNum == 1){ //高位数字 * 当前位数 + 低位数字 + 1 count += HigherNum * Factor + LowerNum + 1; } //如果大于1,出现1的次数由高位决定 else{ //(高位数字+1)* 当前位数 count += (HigherNum + 1) * Factor; } //前移一位 Factor *= 10; } return count; } int main(){ long long int a; while(scanf("%lld",&a) != EOF){ printf("%lld\n",Count(a)); } return 0; }
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));elseSystem.out.println(sum(a) - sum(b-1));}}}
- 【九度OJ1373】|【剑指offer32】整数中1出现的次数(从1到n整数中1出现的次数)
- 【剑指Offer面试题】 九度OJ1373:整数中1出现的次数(从1到n整数中1出现的次数)
- 剑指offer32:从1到n整数1出现的次数
- 整数中1出现的次数(从1到n整数中1出现的次数)
- 《剑指offer》整数中1出现的次数(从1到n整数中1出现的次数)
- 剑指offer--整数中1出现的次数(从1到n整数中1出现的次数)
- 剑指Offer--032-整数中1出现的次数(从1到n整数中1出现的次数)
- [剑指offer]整数中1出现的次数(从1到n整数中1出现的次数)
- 剑指offer-整数中1出现的次数(从1到n整数中1出现的次数)
- 剑指Offer:整数中1出现的次数(从1到n整数中1出现的次数)
- 剑指Offer_31_整数中1出现的次数(从1到n整数中1出现的次数)
- 剑指offer:整数中1出现的次数(从1到n整数中1出现的次数)
- 剑指offer----整数中1出现的次数(从1到n整数中1出现的次数)
- 剑指offer-整数中1出现的次数(从1到n整数中1出现的次数)
- 剑指offer 整数中1出现的次数(从1到n整数中1出现的次数)
- 剑指offer-31.整数中1出现的次数(从1到n整数中1出现的次数)
- 【剑指offer】整数中1出现的次数(从1到n整数中1出现的次数)
- 《剑指offer》整数中1出现的次数(从1到n整数中1出现的次数)
- Htpp通讯——Java实现
- HDU 5289 Assignment (二分+区间最值)
- 08-排序3. Talent and Virtue (25)
- 自定义BaseAdapter
- CheckBox,ImageView,ListView
- 【九度OJ1373】|【剑指offer32】整数中1出现的次数(从1到n整数中1出现的次数)
- UITextField 弹出键盘的外观(类型)设置
- ARM处理器启动流程
- Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call
- 【cocos2d-x 3.7 飞机大战】 决战南海I (十) 游戏主场景
- Android的控件CheckBox、ImageView以及ListView的自定义Adapter用法
- 解决双系统下如何完全卸载Ubuntu系统
- 编写高质量代码--改善Java程序的151个建议
- js 获取事件对象以及元素