Task 10 统计从1到某个整数之间出现的1的次数
任务:给定一个十进制的正整数,写下从1开始,到N的所有整数,然后数一下其中出现“1”的个数。
要求: 写一个函数 f(N) ,返回1 到 N 之间出现的 “1”的个数。例如 f(12) = 5。
在32位整数范围内,满足条件的“f(N) =N”的最大的N是多少。
1.设计思想:因为上课很多同学都给出了一个一个数地求出所出现的1,最多每个数也就求5、6次,但是所给的整数很大的时候计算机会一下循环递归N次来计算1的次数,这样会导致效率非常低。我们都知道每个位数上都有一定的规律,每一位上出现1的次数都和其前一位和后一位以及当前位上的数字有关系,所以得通过大量的数据一位一位的进行分析,进而找到每个数的规律。

通过对1位数、2位数、3位数,,,进行分析统计,发现如果当前位上的数字为0,1,大于等于1时有不同的情况;则此位上出现的1的次数分别会由更高位数上、更低位或者当前位的数字决定,具体如下:
假设一个数为abcde
如果百位上数字c为0,百位上可能出现1的次数由更高位决定。比如:33033,则可以知道百位出现1的情况可能是:100~199,1100~1199,2100~2199,,.........,32100~32199,一共3300个。可以看出是由更高位数字(12)决定,并且等于更高位数字(ab)乘以 当前位数(100)。
如果百位上数字为1,百位上可能出现1的次数不仅受更高位影响还受低位影响。比如:33133,则可以知道百位受高位影响出现的情况是:100~199,1100~1199,2100~2199,,.........,32100~32199,一共3300个。和上面情况一样,并且等于更高位数字(ab)乘以 当前位数(100)。但同时它还受低位影响,百位出现1的情况是:33100~33133,一共134个,等于低位数字(cde)+1。
如果百位上数字大于1(2~9),则百位上出现1的情况仅由更高位决定,比如12213,则百位出现1的情况是:100~199,1100~1199,2100~2199,...........,11100~11199,12100~12199,一共有1300个,并且等于更高位数字+1(ab+1)乘以当前位数(100)。
除了百位上其他位数也都符合这个规律,所以只需要循环整数的位数次就可以求出最终的结果。
然后第二步实现的时候,开始以为只需要一个循环就行了,让计算机循环。不过由于基数太大所以会用很长时间
将要计算的范围划分为几个区间,然后对每个区间进行计算。比如说:
1到999,先将这些数划分为10个区间:1-99、100-199 … 900-999
由f(999) = 300可知,300以后的区间段可以不计算。当计算200时,可以先计算299,由于f(299)=160<200,200-299的区间可以都不必计算。对要计算的区间,再将它划分为10个区间,重复进行。这样划分的另一个好处是利用公式:f(10^n-1) = n * 10^(n-1),保存上次算得的f(n)直接计算下个数的f(n)。
2.源代码:
#include<iostream>
using namespace std; int Count(int n){ int count = ;//1的个数 int CurrentPosition = ;//当前位 int LowerNum = ;//低位数字 int CurrNum = ;//当前位数字 int HigherNum = ;//高位数字 while(n / CurrentPosition != )
{
LowerNum = n - (n / CurrentPosition) * CurrentPosition;//低位数字 CurrNum = (n / CurrentPosition) % ;//当前位数字 HigherNum = n / (CurrentPosition * );//高位数字 if(CurrNum == )//如果为0,出现1的次数由高位决定
{
count += HigherNum * CurrentPosition;//等于高位数字 * 当前位数
} else if(CurrNum == )//如果为1,出现1的次数由高位和低位决定
{
count += HigherNum * CurrentPosition + LowerNum + ;//高位数字 * 当前位数 + 低位数字 + 1
} else//如果大于1,出现1的次数由高位决定
{
count += (HigherNum + ) * CurrentPosition;//(高位数字+1)* 当前位数
} CurrentPosition *= ;//前移一位
}
return count;
} void main()
{
int a;
cout << "请输入一个正整数:";
cin >> a;
cout << a;
cout << "从1到该数字出现的1的次数为:" << Count(a) << endl;
for (int i = ; i < ; i++)
{
if( Count(i) == i)
{
cout << i << " ";
} }
}


改进之后:
#include<iostream>
using namespace std; int Count(int n){ int count = ;//1的个数 int CurrentPosition = ;//当前位 int LowerNum = ;//低位数字 int CurrNum = ;//当前位数字 int HigherNum = ;//高位数字 while(n / CurrentPosition != )
{
LowerNum = n - (n / CurrentPosition) * CurrentPosition;//低位数字 CurrNum = (n / CurrentPosition) % ;//当前位数字 HigherNum = n / (CurrentPosition * );//高位数字 if(CurrNum == )//如果为0,出现1的次数由高位决定
{
count += HigherNum * CurrentPosition;//等于高位数字 * 当前位数
} else if(CurrNum == )//如果为1,出现1的次数由高位和低位决定
{
count += HigherNum * CurrentPosition + LowerNum + ;//高位数字 * 当前位数 + 低位数字 + 1
} else//如果大于1,出现1的次数由高位决定
{
count += (HigherNum + ) * CurrentPosition;//(高位数字+1)* 当前位数
} CurrentPosition *= ;//前移一位
}
return count;
} inline unsigned count_digits(unsigned long long num)
{
unsigned long long n = ;
unsigned ret = ;
while (n <= num) { n *= ; ++ret; }
return ret;
} void get_nums()
{ unsigned long long x = 1e11 - , y;
unsigned count = ;
unsigned idx = ;
while (true)
{
++count;
y = Count(x);
if (x < y)
{ //x在1到10时,均不满足x<y,所以x>10,下面的k值肯定大于0
unsigned k = count_digits(x) - ;
x -= (y - x - )/k + ;
}
else if (x > y) { x = y; }
else
{
cout<< ++idx << ": " << x << endl;
//break;
--x;
if (x == ) break;
}
}
} void main()
{
int a;
cout << "请输入一个正整数:";
cin >> a;
cout << a;
cout << "从1到该数字出现的1的次数为:" << Count(a) << endl;
cout << "整数与次数相同的有以下这些,最大值为第一个数:";
get_nums();
}
3.实验截图:

4.实验总结:
(1)这个题目跟之前的同样是数学题类型的程序,需要利用大量的来分析统计,从中得出规律,否则就失去了编程的高效性;
(2)而当完成第一步之后以为第二步很简单,其实不然。感觉当时一定是被成功的喜悦蒙蔽了双眼,只是看它一直在滚动数字,而且也得出了最后的结果,然而却没想到效率的问题,之才发现第二步的设计也包含了好多规律,所以一定要从头到尾保持清醒的头脑。
Task 10 统计从1到某个整数之间出现的1的次数的更多相关文章
- C# IP地址与整数之间的转换
IP地址与整数之间的转换 1.IP地址转换为整数 原理:IP地址每段可以看成是8位无符号整数即0-255,把每段拆分成一个二进制形式组合起来,然后把这个二进制数转变成一个无符号的32位整数. 举例:一 ...
- [c++]大数运算1---利用C++ string实现任意长度正小数、整数之间的加减法
一.概述 本文属于大大维原创,未经笔者本人允许,严禁转载!!! C/C++中的int类型能表示的范围是-2E31-2E31–1.unsigned类型能表示的范围是0-2E32–1,即 0-429496 ...
- [c++]大数运算---利用C++ string实现任意长度正小数、整数之间的加减法
本文为大大维原创,最早于博客园发表,转载请注明出处!!! 一.概述 C/C++中的int类型能表示的范围是-2E31-2E31–1.unsigned类型能表示的范围是0-2E32–1,即 0-4294 ...
- 1到n的整数中,1出现的次数
参考链接:https://discuss.leetcode.com/topic/18054/4-lines-o-log-n-c-java-python 1到n的整数中,1出现的次数,如11中,1出现了 ...
- C语言中的字符和整数之间的转换
首先对照ascal表,查找字符和整数之间的规律: ascall 控制字符 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 56 8 ...
- (算法)从0到n整数中数字2出现的次数
题目: 数出0到n(含)中数字2出现了几次. 思路: 1.暴力方法,数出每个数字包含几个2,然后累加起来. 2.分析:分别考虑数字n每一位出现2的次数,如123123: 从左往右考虑4123123: ...
- 输入n行整数,每行的个数不确定,整数之间用逗号分隔
/*===================================== 输入n行整数,每行的个数不确定. 每行内部两个数之间用逗号隔开. 例如输入数据如下: 6 1,3,5,23,6,8,14 ...
- 从1到整数n中1出现的次数
题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数.例如输入12,从1到12这些整数中包含1的数字有1,10,11和12共出现了5次. 不考虑时间效率的解法: int Numbe ...
- python实例:利用jieba库,分析统计金庸名著《倚天屠龙记》中人物名出现次数并排序
本实例主要用到python的jieba库 首先当然是安装pip install jieba 这里比较关键的是如下几个步骤: 加载文本,分析文本 txt=open("C:\\Users\\Be ...
随机推荐
- CentOS 6.4 编译安装 gcc 4.8.1
今天在isocpp上看到“GCC 4.8.1 released, C++11 feature complete”这个消息,非常兴奋.终于有一个全面支持C++11语言特性的编译器了! 当然了,gcc仅仅 ...
- javaScript真值和假值以及相等操作符
真值和假值 相等操作符(==和===) 下面分析一下不同类型的值用相等操作符(==)比较后的结果 toNumber 对不同 类型返回的结果如下: toPrimitive 对不同类型返回的结果如下: = ...
- jquery,字符串转json对象,json对象转字符串
字符串转json对象 方法一:var json = eval('(' + str + ')'); 方法二:return JSON.parse(str); json对象转字符串 JSON.stringi ...
- nRF52832 改变ATT_MTU提高蓝牙数据发送速率(nRF5_SDK_14.2.0)
nRF52832 作为一个低功耗蓝牙芯片,其数据发送发送速率一直都偏低(高就不叫低功耗了^_^),作为初学者在网上找了很多资料,终于找到通过修改ATT_MTU来提升发送速率的方法,最快能达到8.2KB ...
- 时间序列深度学习:状态 LSTM 模型预测太阳黑子
目录 时间序列深度学习:状态 LSTM 模型预测太阳黑子 教程概览 商业应用 长短期记忆(LSTM)模型 太阳黑子数据集 构建 LSTM 模型预测太阳黑子 1 若干相关包 2 数据 3 探索性数据分析 ...
- ZooKeeper实现分布式队列Queue
ZooKeeper实现分布式队列Queue 让Hadoop跑在云端系列文章,介绍了如何整合虚拟化和Hadoop,让Hadoop集群跑在VPS虚拟主机上,通过云向用户提供存储和计算的服务. 现在硬件越来 ...
- SCP命令小例子
磨砺技术珠矶,践行数据之道,追求卓越价值 回到上一级页面: PostgreSQL杂记页 回到顶级页面:PostgreSQL索引页 [作者 高健@博客园 luckyjackgao@gmail. ...
- P2154 [SDOI2009]虔诚的墓主人
略有一点点思维的题. 首先,如果一个点上,下,左,右分别有\(a,b,c,d\)棵树,那这个点的十字架方案为\(C_{a}^{k}C_{b}^{k}C_{c}^{k}C_{d}^{k}\). 按x坐标 ...
- noip2017 TG 游记
嗨小朋友们大家好,还记得我是谁吗?我就是为GG代言的蒟蒻--xzz 今天呐我特别的要向HN的dalao们ZJ的巨佬们还有全国的神犇们问声好 为什么呢因为我们在2017年11月份来到了吔屎的长沙理工大学 ...
- Hbase第五章 MapReduce操作HBase
容易遇到的坑: 当用mapReducer操作HBase时,运行jar包的过程中如果遇到 java.lang.NoClassDefFoundError 类似的错误时,一般是由于hadoop环境没有hba ...