作业1 2020

1.作业头

这个作业属于哪个课程 https://edu.cnblogs.com/campus/zswxy/CST2020-3
这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2020-3/homework/11768
我在这个课程的目标是 回顾数据类型和表达式 文件
学号 20209031
ps: 优化写在最末尾

二、本周作业(总分:50分)

2.1 题目:给定一个十进制正整数N,写下从1开始,到N的所有整数,然后数一下其中出现的所有“1”的个数。

例如:

N=2,写下1,2。这样只出现了1个”1“。

N=12,我们会写下1,2,3,4,5,6,7,8,9,10,11,12。这样,1的个数是5。

问题是:

1.写出一个函数f(N),返回1到N之间出现的”1“的个数,比如f(12)=5;

2.满足条件”f(N)=N“的最大的N是多少?

要求:

1.贴出代码图片,写出解题思路,列出测试数据(5分)

解题思路:通过1到n的循环逐次判断并累加count变量
测试数据 结果
12 5
3594 2120
9999 4000
2.给出不同测试数据的运算时间,如果你的运算时间不变,说明你的测试数据不够大(5分)
2.2 将上题中多组测试数据写入文件,并给出测试程序以检测你的代码有没有问题,贴出你的代码、运行结果和文件内容。(5分)

2.3 用自己的语言回答两个问题,并给出所查阅资料的引用(10分)
1.什么是文件缓冲系统?工作原理如何?

1.指针对原件进行管理和访问以减少对磁盘的实际读写次数.
2.系统会自动的在内存区为每一个正在使用的文件开辟一块缓冲区。从此盘向内存读数据时,则一次将一些数据从磁盘文件送内存缓冲区(充满缓冲区),然后再从缓冲区逐个将数送给接收变量(文件描述
符);从内存写数据到磁盘文件时,现将数据塞满缓冲区,在一次性将数据从缓冲区送到磁盘文件

2.什么是文本文件和二进制文件?

1.文本文件是一种计算机文件,将键入的文档存储为一系列字母和数字字符,通常没有可视化的格式化信息。直接翻译成人类可读的文本。
2.二进制文件是由一批同一类型的数据组成的一个数据序列,就是说一个具体的二进制文件只能存放同一种类型的数据。由计算机直接解释。

2.4 请给出本周学习总结(15分)
1 学习进度条(5分)

周/日期 时间 代码行数 学习内容 疑惑
1/3.3 20 200 文件 数据结构 文件 数据结构
2 累积代码行和博客字数(5分)

3 学习内容总结和感悟(5分)
数据结构的学习需要耗费大量的时间 并多次实践 在算法的学习上要更家巩固基础

思考针对足够大的数据,如何减少运算时间,并给出在原有算法基础上的改进算法和改进思路。(10分)

思路:当数据非常大的时候,利用for循环进行枚举判断的暴力解法会让时间复杂度变得非常大 所以列举多个数字欲模拟程序以找出数学规律顺序
例如将1-100当中的含有1的数字列举出来
1 10 11(11含有两个1) 12 13 14 15 16 17 18 19 21 31 41 51 61 71 81 91 100 共计21个1
按照个位十位百位划分
个位中有1的数字: 1 11 21 31 41 51 61 71 81 91
十位中有1的数字: 10 11 12 13 14 15 16 17 18 19
百位中有1的数字: 100
则猜测若列举 1-1000的数字
1-10中 个位数中 1出现1次
1-100中 十位数中 1出现10次
1-1000中 百位数中 1出现100次
如 列举1234
个位满十进十 每1-10中 个位数中 1出现1次 从1-1230包含123个10 则1出现123次 又个位上的4>1 则包含有一个个位上的1 共123+1=124次
十位满十进百 每1-100中 十位数中 1出现10次 从1-1200中出现12个100 则1出现120次 十位上3>1 则包含有一个十位上的(10-19)10个1 共130次
百位满十进前 每1-1000中 百位数中 1出现100次 从1-1000中共1一个1000 则1又出现100次 百位上2>1 则包含一个百位数上的(100-200)100个1 共200次
千位上 没有更高位数 1=1,所以1000-1234所有的千位都含有1 共出现235个(1000也包含1)
共689个1
例举 5678
个:567+1=568
十:560+10=570
百:500+100=600
千:1000
共2738


总结规律得到
以1234为例
右数第i个数字与1比较 若i>1 则以(i左边的数字)+ 10的(i-1)次方 若i=1则以(左边的的数字)+(右边的数字)+1
以此数学规律为思路 优化算法并实现代码

#include<iostream>
#include<time.h>
#include<stdio.h>
#include<math.h>
using namespace std;
int seek(int n) {
int a[100] = { 0 };
int p = n, count = 0;;
while (p != 0) {
a[count] = (p % 10);
p /= 10;
count++;
}
int i = 0;
int sum=0;
while (count != 0) {
int l = (n / pow(10, i + 1));
l = l *pow(10, i);
if (a[i] > 1) {
sum +=l+pow(10,i);
}
if (a[i] == 1) {
if (count == 1) {
sum += 0 + (n - a[i] * pow(10, 3)) + 1;
}
else {
sum += l + (n - l * 10) + 1;
}
}
i++;
count--;
}
cout << sum<<endl;
return 0;
}
int main(void) {
int n;
clock_t begin, end;
begin = clock();
cin >> n;
seek(n);
end = clock();
double time = (double)(end - begin) / CLOCKS_PER_SEC;
cout << "time =" << time << "s" << endl;
return 0;
}

然后数值过大导致pow的指数过高 超过了int类型 数值太小i和count又导致数组越界 放弃这种思路了

因为个位十位百位等等的拆分 联想到了汉诺塔的递归 可以归结为两种 1.个位和其他位置
1出现的次数为 (个位1出现次数)+(十位1出现次数)+(百位1出现次数)qishi
其实和上面的思路有大部分相同 只是把分割换成了逐位(个十百)

#include<iostream>
#include<time.h>
#include<stdio.h>
#include<math.h>
using namespace std;
void seek(int n) {
    int count = 0;
    int base = 1;
    int round = n;
    while (round > 0) {
        int weight = round % 10;
        round /= 10;
        count += round * base;
        if (weight == 1)
            count += (n % base) + 1;
        else if (weight > 1)
            count += base;
        base *= 10;
    }
    cout << count<<endl;
}
int main(void) {
	int n;
	clock_t begin, end;
	begin = clock();
	cin >> n;
	seek(n);
	end = clock();
	double time = (double)(end - begin) / CLOCKS_PER_SEC;
	cout << "time =" << time << "s" << endl;
	return 0;
}

最大N

根据题目要求 正整数N 所以利用while控制循环条件为0-2147483647进行循环



最大N:1111111110

原文地址:https://www.cnblogs.com/1208712478qq/p/14476854.html