任务:给定一个十进制的正整数,写下从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 = 0;//1的个数int CurrentPosition = 1;//当前位int LowerNum = 0;//低位数字int CurrNum = 0;//当前位数字int HigherNum = 0;//高位数字while(n / CurrentPosition != 0){LowerNum = n - (n / CurrentPosition) * CurrentPosition;//低位数字
        CurrNum = (n / CurrentPosition) % 10;//当前位数字
        HigherNum = n / (CurrentPosition * 10);//高位数字if(CurrNum == 0)//如果为0,出现1的次数由高位决定
        {count += HigherNum * CurrentPosition;//等于高位数字 * 当前位数
        }else if(CurrNum == 1)//如果为1,出现1的次数由高位和低位决定
        {count += HigherNum * CurrentPosition + LowerNum + 1;//高位数字 * 当前位数 + 低位数字 + 1
        }else//如果大于1,出现1的次数由高位决定
        {count += (HigherNum + 1) * CurrentPosition;//(高位数字+1)* 当前位数
        }CurrentPosition *= 10;//前移一位
    }return count;
}void main()
{int a;cout << "请输入一个正整数:";cin >> a;cout << a;cout << "从1到该数字出现的1的次数为:" << Count(a) << endl;for (int i = 0; i < 4294967295 ; i++){if( Count(i) == i){cout << i << "  ";}}
}

改进之后:

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

3.实验截图:

4.实验总结:

(1)这个题目跟之前的同样是数学题类型的程序,需要利用大量的来分析统计,从中得出规律,否则就失去了编程的高效性;

(2)而当完成第一步之后以为第二步很简单,其实不然。感觉当时一定是被成功的喜悦蒙蔽了双眼,只是看它一直在滚动数字,而且也得出了最后的结果,然而却没想到效率的问题,之才发现第二步的设计也包含了好多规律,所以一定要从头到尾保持清醒的头脑。

转载于:https://www.cnblogs.com/mengxiangjialzh/p/4548613.html

Task 10 统计从1到某个整数之间出现的1的次数相关推荐

  1. 本题要求实现一个函数,可统计任一整数中某个位数出现的次数。例如-21252中,2出现了3次,则该函数应该返回3。

    本题要求实现一个函数,可统计任一整数中某个位数出现的次数.例如-21252中,2出现了3次,则该函数应该返回3. 函数接口的定义 int Count_Digit ( const int N, cons ...

  2. 统计个位数字 (本题要求实现一个函数,可统计任一整数中某个位数出现的次数。例如-21252中,2出现了3次,则该函数应该返回3)

    5.本题要求实现一个函数,可统计任一整数中某个位数出现的次数.例如-21252中,2出现了3次,则该函数应该返回3. 实现代码: int Count_Digit ( const int N, cons ...

  3. C# IP地址和整数之间的转换,IP地址和数字ip地址的转换

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

  4. 第五节:Task构造函数之TaskCreationOptions枚举处理父子线程之间的关系。

    一. 整体说明 揭秘: 通过F12查看Task类的源码(详见下面的截图),发现Task类的构造函数有有一个参数为:TaskCreationOptions类型,本章节可以算作是一个扩展章节,主要就来研究 ...

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

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

  6. 软件的基本是要处理好”算法“及其基础(一)流-字-字符(包括某个数字、字母、符号和某个汉字等)-字符串-字节动态数组-字节-整数之间的转化关系和算法

    目录 软件的基本是要处理好"算法"及其基础(一): 流->计算机字->字符(包括某个数字.字母.符号和某个汉字等)->字符串->字节动态数组->字节- ...

  7. C语言: 定义一个函数int isprime(int n),用来判别一个正整数n是否为素数。在主函数中输入两个正整数m和n(m>=1,n>m),统计并输出m和n之间的素数的个数以及这些素数的和。

    原题: 定义一个函数int isprime(int n),用来判别一个正整数n是否为素数.在主函数中输入两个正整数m和n(m>=1,n>m),统计并输出m和n之间的素数的个数以及这些素数的 ...

  8. 日期类对象与整数之间的加法运算

    日期类对象与整数之间的加法运算 采用友元函数形式, 定义两个友元函数

  9. Java实现 String类型的ip与整数之间的相互转换(2021.8.1百度提前批面试题)

    题目: 实现 String 类型的 ip 与整数之间的相互转化.例如:将 "192.168.0.1" 转换为整数,然后给定这个整数仍然可以得到这个 String 类型的 ip. / ...

最新文章

  1. 2022-2028年中国树脂行业市场研究及前瞻分析报告
  2. 程序员:提高编程效率的技巧
  3. 安装和使用Smokeping(二)
  4. 50个国内外最棒的C/C++源码站点分享
  5. oc09--NSString
  6. 人脸识别 轻量级高精度网络推荐
  7. 20181127-1附加作业 软件工程原则的应用实例
  8. 算法提高课-搜索-Flood fill算法-AcWing 1106. 山峰和山谷:flood fill、bfs
  9. SpringBoot实现Java高并发秒杀系统之DAO层开发(一)
  10. 爱我少一点,我请求你
  11. graphpad怎么修改图片大小_Graphpad Prism 8.0进阶篇-绘制小提琴图
  12. .NET平台下几种SOCKET模型的简要性能供参考
  13. MIS 740: Software Concepts Use different GUI components i
  14. CPLEX-求解VRPTW模型
  15. 【参考】MTK线刷工具错误代码大全及解决方法
  16. 调整视频播放速度,如何让视频加速或放慢播放
  17. 历届博客之星获奖博客分享
  18. javascript与css压缩工具
  19. python将excel转换成图片_python-尝试将Excel文件保存为图片并加上水印-阿里云开发者社区...
  20. 抖音数据分析(基于播放、点赞、投稿、背景音乐)--pyecharts可视化

热门文章

  1. ViewPager实现页面切换
  2. Linq to Sql 动态条件另类实现方法
  3. 疯狂ios讲义疯狂连载之实现游戏视图控制器
  4. lwuit ---一些细节疑难杂症整理笔记
  5. Eclipse运行Applet没有显示图片,getCodeBase,getDocumentBase
  6. RobotFramework自动化框架—robot文件中调用自定义库
  7. Android App Bundle:动态功能模块
  8. yii2 发送邮件 yii\swiftmailer\Mailer
  9. 【硬件】集线器,交换机,路由器
  10. 7-1 抓老鼠啊~亏了还是赚了? (20 分)