任务:给定一个十进制的正整数,写下从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的次数的更多相关文章

  1. C# IP地址与整数之间的转换

    IP地址与整数之间的转换 1.IP地址转换为整数 原理:IP地址每段可以看成是8位无符号整数即0-255,把每段拆分成一个二进制形式组合起来,然后把这个二进制数转变成一个无符号的32位整数. 举例:一 ...

  2. [c++]大数运算1---利用C++ string实现任意长度正小数、整数之间的加减法

    一.概述 本文属于大大维原创,未经笔者本人允许,严禁转载!!! C/C++中的int类型能表示的范围是-2E31-2E31–1.unsigned类型能表示的范围是0-2E32–1,即 0-429496 ...

  3. [c++]大数运算---利用C++ string实现任意长度正小数、整数之间的加减法

    本文为大大维原创,最早于博客园发表,转载请注明出处!!! 一.概述 C/C++中的int类型能表示的范围是-2E31-2E31–1.unsigned类型能表示的范围是0-2E32–1,即 0-4294 ...

  4. 1到n的整数中,1出现的次数

    参考链接:https://discuss.leetcode.com/topic/18054/4-lines-o-log-n-c-java-python 1到n的整数中,1出现的次数,如11中,1出现了 ...

  5. C语言中的字符和整数之间的转换

    首先对照ascal表,查找字符和整数之间的规律: ascall 控制字符  48  0  49  1  50  2  51  3  52  4  53  5  54  6  55  7  56  8 ...

  6. (算法)从0到n整数中数字2出现的次数

    题目: 数出0到n(含)中数字2出现了几次. 思路: 1.暴力方法,数出每个数字包含几个2,然后累加起来. 2.分析:分别考虑数字n每一位出现2的次数,如123123: 从左往右考虑4123123: ...

  7. 输入n行整数,每行的个数不确定,整数之间用逗号分隔

    /*===================================== 输入n行整数,每行的个数不确定. 每行内部两个数之间用逗号隔开. 例如输入数据如下: 6 1,3,5,23,6,8,14 ...

  8. 从1到整数n中1出现的次数

    题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数.例如输入12,从1到12这些整数中包含1的数字有1,10,11和12共出现了5次.   不考虑时间效率的解法: int Numbe ...

  9. python实例:利用jieba库,分析统计金庸名著《倚天屠龙记》中人物名出现次数并排序

    本实例主要用到python的jieba库 首先当然是安装pip install jieba 这里比较关键的是如下几个步骤: 加载文本,分析文本 txt=open("C:\\Users\\Be ...

随机推荐

  1. where语句中不能直接使用聚合函数

    1.问题描述 select deptno ,avg(sal) from emp where count(*)>3 group by deptno; 在where 句中使用聚合函数count(*) ...

  2. OpenJudge 4001:抓住那头牛

    题目链接 题解: 这个题可以用广搜来解决,从农夫到牛的走法每次都有三种选择,定义一个队列,把农夫的节点加进队列,然后以这三种走法找牛,队列先进先出,按顺序直到找到牛的位置. 代码: #include& ...

  3. 20155236范晨歌_exp6信息搜集与漏洞扫描

    20155236范晨歌_exp6信息搜集与漏洞扫描 目录 实践目标 信息搜集 漏洞扫描 总结 实践目标 (1)各种搜索技巧的应用 (2)DNS IP注册信息的查询 (3)基本的扫描技术:主机发现.端口 ...

  4. 对control file的学习笔记

    SQL> startup nomount;startup nomount;ORACLEインスタンスが起動しました. Total System Global Area 521936896 byte ...

  5. Noip前的大抱佛脚----赛前任务

    赛前任务 tags:任务清单 前言 现在xzy太弱了,而且他最近越来越弱了,天天被爆踩,天天被爆踩 题单不会在作业部落发布,所以可(yi)能(ding)会不及时更新 省选前的练习莫名其妙地成为了Noi ...

  6. 3、计数排序,电影top100

    1.计数排序 # -*- coding: utf-8 -*- # @Time : 2018/07/31 0031 11:32 # @Author : Venicid def count_sort(li ...

  7. 约束4:唯一约束,Check约束和null

    大家知道,关系型数据库的逻辑运算的结果是三值型的,TRUE,FALSE和UNKNOWN,特别是,NULL值和任何值都不相等,任何值和NULL的比较,返回的逻辑结果都是unknown.而NULL值在唯一 ...

  8. Java JDK下载安装及配置

    下载JDK(Java Development Kit),所有的Java程序都依赖他. 下载地址 www.oracle.com  直接下载 安装JDK如图(傻瓜式安装,下一步下一步):   安装完成后 ...

  9. 用CSS中的Alpha实现渐变

    效果一:<div  id="Layer1"  style="position:absolute;  left:161px;  top:160px;  width:2 ...

  10. 微信小程序中的分享事件

    小程序的分享 onShareAppMessage(options)   在页面的js文件中定义了 onShareAppMessage 函数时,页面可以表示改页面可以转发.可以在函数中设置页面转发的信息 ...