算法错题本

本文总结了编程中常见的错误陷阱,包括全局变量与局部变量的区别、数据操作中的注意事项、无解情况处理策略、输入和数组管理、链表操作、循环体中的类型和初始化、队列操作限制、字符串处理、数学计算技巧以及遍历和查找算法的应用。
摘要由CSDN通过智能技术生成

这里写目录标题

错题本

注意全局变量与main函数第一个局部变量的区别

在这里插入图片描述
虽然,从main函数运行的逻辑来看,n是在函数内是可见的,但是对于程序的编译来看,函数的定义写在上面,所以,不可见n,所以,可以将n放在全局变量区,不影响程序且函数可见

注意在求某个结果mod一个数时

如果某一步出现 减法,那么该步最好在减完之后,再加上mod的那个数,最终括起来再mod那个数,这样可以保证不为负数
如下图:
在这里插入图片描述

注意数据的耦合性

在这里插入图片描述
bfs求连通块的时候,在进入四个方向搜索时,要注意,每次得到的新的x,y,一定不要与原x y 有任何的瓜葛,要保证每次for循环都是在旧的x y的基础上进行修改的,如果我们将x1 y1改为了x y,那么每次x y都会被更新,这显然是错的

对于无解情况的处理思路

在这里插入图片描述
利用反证法:如上代码,可以在有解的时候,将全局变量res,改为true,这样的话,只要有一组有解,那么就不会输出无解,反之,没有任何解的情况下,就会无解。
这里也可以注意到,全局变量使用时,不仅要关注其自动初始化为0,还要关注,他的变量是全局的,他会累计值,所以,何时该用全局,何时该用局部,要进行衡量
同时也要注意,对于一些比例的验证,最好用乘法,实际上,任何除法的计算,如果可以转化为乘法,那是最好的

一组数据以0为结束标记,如何输入到数组中,并计数

在这里插入图片描述
输入时,先将nums[0]输入,然后进行循环,循环时,定义ij 两个循环变量 i初始化为0,j初始化为1,之后i j都要递增,结束条件是nums[i]!=0,这样可以确保结束条件的生效,不然如果只用 i 的话,nums[i]还没被赋值就拿去判断是否等于0了。
总结:循环外输入nums[0], i 始终比 j 小一,结束条件用i判断,输入语句用 j

多个数据进行比较

在这里插入图片描述
可以先设一个很大的数(超过本题数据范围的数)
在一个循环里,将每个数据依次在一次循环中得出,每次循环得到的结果是x,将x与ans取min,赋值给ans,这样多次循环之后,就是多个数据的最小值

链表删除重复元素的启发

在这里插入图片描述
图中 1、对于链表 可能系统会传入空指针进去 所以要考虑到 要加上空指针判断
2、对于while条件的设置 因为p不可以指到空指针 不然出错 所以不可以设置为p!=NULL 但是p必须最终指向最后一个结点来结束循环 所以可以设置为p->next!=NULL;
3、因为执行完if中的内容之后 还要再比较一遍处理过后的当前结点的情况 所以 在if为真时 不设置p后移
而是在else里设置p后移 这样既可以再比较一遍 还符合运行逻辑

循环体里谨慎写类型定义并初始化(一般写上就是错)

在这里插入图片描述
上图中 在循环里 不要定义int i = 0 ;
这样的话每次循环都会使其为0;
低级错误 只能在for循环里设置为int i= 0;

队列中读取队尾元素

在这里插入图片描述

数组当做形参传递到函数里之后 就不可以进行数组元素的计算了

在这里插入图片描述
sizeof(nums)/sizeof(nums【0】) 可以算出数组的元素个数
但是仅限于在定义数组的函数内才可以
注意:sizeof的办法不能求已经定义好的数组的长度 因为这样的话 sizeof(数组)就是你定义的长度的字节数

如果将数组作为形参 传递到函数里 那么就不可以用这种方法 因为一旦当做形参传递数组 数组就变成了指针 就不会传入整个数组的大小 所以不可以在函数里求函数外的数组的元素个数 只能在函数外求出 然后当做形参传递进去

当数组定义好了长度 如何求有效长度

利用for循环 计数器++ 求长度
终止条件(跳出循环条件):
在这里插入图片描述
可以看到定义好了数组之后 不赋值的地方 就是乱码 以此为终止条件
在这里插入图片描述

读取字符串越界位置

在这里插入图片描述
越界位置为NULL

返回值是一个容器

在这里插入图片描述
当返回值是一个容器时 就要返回一个同类型的容器 可以定义一个函数 在函数里进行操作 之后的输出替换成向容器里面加入元素即可

ps 适用于某个算法在递归输出 而没有返回值时 可能会遇到这种情况

持续删除string中某个字符

在这里插入图片描述
首先拿到第一个pos = A.find(目标字符)
之后while循环中,如果pos不等于尾后迭代器(这里是string::npos),就一直循环
A.erase(pos, 1);
之后在循环内更新pos = A.find(还是那个目标字符)

蓝桥真题

快速幂计算a^k % p

当p超过其能表示的最大范围时,他就相当于没有%p,因为%p会让结果在p的范围内,只要p足够大,就不会产生%p的实质效果

尽量不要在循环条件做手脚,在循环内进行continue

在这里插入图片描述

判断double相等

double不要用==,而是用<0.00001 && > - 0.00001

或者使用abs(double x)< 0.000001

至于0.00001是几位小数,看x的小数再加一位小数或者两位,但不是越多越好,有时候多了反而无法出值

位运算

& 、 | 都是以1的视角来判断即可
0 & 0 = 0,而不是0 & 0 = 1

scanf输入时,注意%d的个数

在这里插入图片描述
一定要注意%d的数量与变量数量匹配!!!

日期查重(两个错误)

1、在进行常识性判断时,不应该使用for循环限制月份
在这里插入图片描述
如果这样的话,一个月份只能判断一次,也就是如果有一个m对应多个d,那么当第一个d判断完之后,for循环就强制进入++m的判断了,所以,这里直接进行合理性判断即可,又快又对,如下:
在这里插入图片描述
2、日期是否出现过
在这里插入图片描述
这样的查重也是不对的,如果有4月20号进入,那么月份中的4月被记录,日期中的20被记录,虽然我们是判断当月份和日期都存在,就返回False,但是如果此时再来一个5月30,会返回true,即没有出现过,正确,但是如果再来一个5月20日,显然,这时月份和日期都存在过,会返回false,明显这是不对的,虽然5和20都已经存在,但是5月20日并没有真正出现过,也就是没有考虑到他们的排列组合问题,

综上,如果题目要求日期一致的话,计一种,那么我们采用对日期进行大循环的方式,比较靠谱,即每个日期出现一次且判断一次

注意break

在这里插入图片描述
如果想实现,找到最小值rmin的下标,且如果有多个最小值,返回前面的那个,那么就要在找到的时候,break,不然imin会一直更新下去,直到循环结束

不要单纯复制pdf上的样例,要看样例与样例之间有无空格

在这里插入图片描述
复制数据之前,要看看,数据之间有没有空格,必须有空格 不然会认为是一个int

谁来当大遍历

在这里插入图片描述
在这里插入图片描述
相同的日期统计一次,那么就对所有的日期进行大遍历,保证日期只判断一次,即可。

且,如果需要使用局部数组,直接在函数内定义即可,定义数组很方便的,但是注意要初始化,如果有值,初始化为特定值,如果没有int n[30] = { 0 };要初始化一个数据为0,这样其他都是0

同时可以学习一下,判断一个数组与另一个数组中所有的数据都相匹配的判断:(见上图的最后一个for循环)
每当有一位匹配时,就将k++,继续下一位的匹配,而在每次匹配成功,都要判断是不是最后一位匹配成功,即 k == 数组长度(因为一旦成功,k++,k就是下一次的准备数据,所以可以直接判断是否k = = 数组长度,而不是数组长度 - 1)

四舍五入小数

在这里插入图片描述
*100进行四舍五入,之后再/100
对于整数而言,可以使用round,或者printf(“%.0f”)

使用.0四舍五入时,要用.0f,而不是.0d

因为四舍五入必然是对double变量做的,所以,肯定是.0f
在这里插入图片描述

局部数组也要进行初始化,不然会随机带值

在这里插入图片描述

如果要用到n,那么n–之前要先将值存起来

在这里插入图片描述
原代码是res1 / n,显然,n在上面的循环内已经变小了,此时的n已经不是彼时的n了

for循环的循环条件最好先用一个变量接收,不然会忽略其数据在for循环执行过程中进行了改变

在这里插入图片描述这个for循环,在每次判断是否 i < q.size时,q.size都会改变,因为循环中有个pop
所以,在进行循环之前就将其赋值给r,如下图,即可
在这里插入图片描述

粗心

在这里插入图片描述
第一:审题不全,题目并不是每次都读入三个字符串,而是根据s1的内容,来决定接下来读入s2、s3还是只读入s3
第二:细节不够,题目要求判断大写,结果写成了小写,导致错误

dfs

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
知识点1:本题在dfs的for循环搜索中,进行了剪枝,即写一个判断函数,把不符合题意的情况直接continue,进行下一个数据的搜索
知识点2:在剪枝时,判断边界:直接对x,y在有效范围进行了判断,这样可以不必设置边界为-1
知识点3:剪枝中,会用到已经放置的位置,所以本题需要地图,定义g数组
知识点4:dfs时,虽然每次dfs可以将整个地图覆盖了,但是仍然需要回溯g的值,本质原因是因为要用g的值(是1还是0)来进行剪枝,所以g的值相当重要,需要回溯(tip:无论是否需要,都将值进行回溯就可以了,他主要的作用过程是,深搜搜到底之后,向上返回层数时,每个位置都被回溯成回溯的值)如下图:
在这里插入图片描述
而不回溯则是:
在这里插入图片描述
回溯时不管他的值是多少,等待下一次dfs直接覆盖掉
显然,我们直接统一进行回溯即可

知识点5:因为起点不确定,所以还要对起点进行手动遍历设置到地图上,但是这样的话,就相当于已经完成了一层,传入层数时传入1,进行第二层的搜索即可
dfs出来之后,也要将起点恢复成0,因为g是全局数组,不恢复会影响下一次起点的程序

巧用计数数组来判断哪个数重了

在这里插入图片描述

当样例没有文件结束符时,就要使用getchar()来进行判断结束了

在这里插入图片描述
注意,getchar是在当前循环步所有的工作完成之后,再进行getchar

但是,如果是在竞赛题中,可能他的测试点是带着文件结束符的,但是为了保险起见,还是进行getchar来获取特殊字符结束吧。
如果没办法通过getchar或者其他手段结束,那么直接交上去,说不定也是对的(根据数据还有题意猜测哪里可能会有文件结束符)

对全局变量修改时,尤其是数组,要注意修改之后,数据会长久保留,所以一定要考虑本次修改是否会影响后续的代码

在这里插入图片描述

在这里插入图片描述

遇到简单的组合数问题

在这里插入图片描述
在这里插入图片描述

遇到如上图所示,cab中,已经给出了a或者b的值,且a或者b的值很小,那么可以直接把组合数的数学公式推出来,计算即可了,不用局限于写上模版,然后代数。

取模和除法、补充前导0

在这里插入图片描述
%:a % b
1、a除以b之后的余数
2、a 减去 b的整数倍 之后,在b范围内的数
3、a % b == 0,a 是 b 的整倍数
4、a % 10,小数点左移一维,取右边的数

/ :a / b
1、a除以b的结果(int数据会缺失精度)
2、a中最多有多少个b
3、a / 10,小数点左移一位,取左边的数

考试的时候细细琢磨
之所以hh、mm、ss后面要%24、60、60,是因为h / (60 * 1000)得到的是一天有多少分钟,而不是一小时的多少分钟,所以要%一小时单位下mm的范围,即%60,ss也要%一分钟下他的范围,%60

同时,该题解还提供了一种补充前导0的办法。printf(“%02d”,x)表示输出两位数字,如果x是个位,就在前面补0,如果x是两位数,则忽略前面那个0

且如果题目没有强调,那么年份和月份都是按照普通情况处理

  • 16
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值