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 ...
随机推荐
- MySQL基础----py全栈
目录 MySQL基础----py全栈 一.引言 1.什么是数据? 2.什么是数据库(DB)? 3.什么是数据库管理系统(DBMS)? 4.什么是数据库系统? 5.数据库管理系统由来 6.什么是数据模型 ...
- easyui div 上下布局 最大化按钮 隐藏标题
背景:easyui在做上下布局的时候,上面是数据列表,下面是数据图表.如下图 需要在上下面板右上角加上最大化按钮,以便可以全屏显示.逻辑就是当上面点击最大化时候,隐藏下面,主意:此时需要将下面的div ...
- Yii2 的安装及简单使用
前段时间第一次使用Yii2框架,碰到了一些问题,这里记录一下. Yii2安装:通过composer安装 1.首先要安装composer,我在另外一篇博客中介绍了如何在Windows下安装compose ...
- JavaWeb基础—JDBC入门
一.什么是JDBC JDBC全称为:Java Data Base Connectivity(java数据库连接),它主要由接口组成 二.JDBC原理概述 JDBC原理:其实就是一组规范(就是对类的规范 ...
- c++ 指针访问数组
用指针访问一维数组 用指针访问二维数组 用指针访问三维数组 一. 用指针访问一维数组 //代码 ; ]={,}; int *p=&a; //int *p=&a[0]; printf(& ...
- POJ-2299 Ultra-QuickSort (树状数组)
题目链接:Ultra-QuickSort 题意: 给出了一个序列,序列中有n个数,现在每次操作能交换相邻的两个数,要求操作几次可以将这个序列转换为一个从小到大排序的序列. 题解: 我的解法是先把所有的 ...
- eclipse - 新建jsp页面默认模板设置
有时候我们自己如果没有现成的JSP模板时,系统一般会自动生成如下页面: 这个页面显然并不是我们所需要的,所以我们需要修改默认模板 进入 修改 <%@ page language="ja ...
- form提交方式Get与Post详解
form作为Html的一个元素,它就是为了客户端提交数据而产生的,它有两个很重要的属性action和method,action属性指明了处理提交的数据的应用程序的URL,而method有两个值:POS ...
- 深入浅出js中的this
Q:this是什么? A:this是Javascript语言的一个关键字,它代表函数运行时,自动生成的一个内部对象,在每个 function 中自动根据作用域(scope) 确定, 指向的是此次调用者 ...
- 使用web api开发微信公众号,调用图灵机器人接口(二)
此文将分两篇讲解,主要分为以下几步 签名校验; 首次提交验证申请; 接收消息; 被动响应消息(返回XML); 映射图灵消息及微信消息; 此篇为第二篇. 被动响应消息(返回XML) 上一篇中,我们已经可 ...