[导读]:超平老师的Scratch蓝桥杯真题解读系列在推出之后,受到了广大老师和家长的好评,非常感谢各位的认可和厚爱。作为回馈,超平老师计划推出《Python蓝桥杯真题解析100讲》,这是解读系列的第51讲。
两数之和,本题是2021年3月27日举办的第12届蓝桥杯青少组Python编程选拔赛真题,题目要求对n个整数,统计任意两个数字和为M的组合数量。
先来看看题目的要求吧。
一.题目说明
编程实现:
给定一组包含n个(n > 3) 正整数数据,和一个正整数M,从这n个正整数中任意拿出两个数相加,相加后的结果正好为M的值,计算出这n个正整数中有多少组这样的数据。
例如:
给定一组正整数为:1, 3, 2, 4,正整数M为 3,其中有1组符合要求,为1和2
给定一组正整数为:2, 7, 11, 6, 13,正整数M为 13,其中有2组符合要求,分别为2 和11,7和6
输入描述:
第一行输入n个正整数,正整数之间英文逗号隔开(正整数不能有重复,且n > 3)
第二行输入一个正整数M
输出描述:
输出n个正整数中两个数相加的结果正好为M的组合有几组
样例输入:
2, 7, 11, 6, 13
13
样例输出:
2
02
二.思路分析
这是一道简单的计算题,考查的知识点主要包括循环、列表和枚举算法。
题目看起来比较简单,就是一个简单的组合问题,每次取两个数字进行组合,判断是否等于M即可。
针对此题,通常有如下3种解决方案:
-
暴力枚举
-
使用combinations()组合函数
-
单循环遍历
第一种方案是暴力枚举,也是最好理解的,但是需要嵌套两层循环,效率不高。
第二种方案则是直接使用combinations()组合函数,代码比较简单,效率也高于暴力枚举。
实际上,还有更简单的方法,这就是第三种方案---单循环遍历,充分利用两数之和的特点即可。
以题目给出的样例数据为例:
nums = [2, 7, 11, 6, 13]
M = 13
我们只需要遍历一次列表,针对每一个列表项nums[i],判断M - nums[i]是否在列表中,并统计数量。
第1次:nums[i] = 2,13 - 2 = 11,在列表中,cnt加1
第2次:nums[i] = 7,13 - 7 = 6,在列表中,cnt加1
第3次:nums[i] = 11,13 - 11 = 2,在列表中,cnt加1
第4次:nums[i] = 6,13 - 6 = 7,在列表中,cnt加1
第5次:nums[i] = 13,13 - 13 = 0,不在列表中,cnt不变
只需要一次循环,就可以统计出所有的排列,如下:
[2,11]
[7,6]
[11,2]
[6,7]
很明显,每一对组合都统计了两遍,需要除以2才是最终的结果。
思路有了,接下来,我们就进入具体的编程实现环节。
三.编程实现
根据上面的思路分析,我们使用3种方案来编写程序:
-
暴力枚举
-
组合函数
-
单循环遍历
1. 暴力枚举
所谓暴力枚举,就是使用两层嵌套循环,代码如下:
代码比较简单,说明一点,在获取正整数列表的时候,利用了map()和list()函数。
map()会根据提供的函数对指定序列做映射,使用如下:
map(function, iterable, ...)
调用map()函数,就是序列iterable中的每一个元素都调用一次function 函数,并将返回结果作为新的序列返回。
需要注意的是,在Python2中,map()函数返回的是列表,而Python 3中返回迭代器,所以需要使用list()函数进行转换。
2. 组合函数
直接使用combinations()函数,代码如下:
代码简单,说明3点:
1). 要先导入combinations()函数;
2). 为了方便,我们将满足条件的组合保存到res列表中,最后只需要输出res列表的长度即可;
3). 这里使用了列表推导式的编程技巧,可以直接使用if条件筛选数据,combinations()函数返回的是元组,此处使用list()函数将其转成列表,也可以直接作为元组返回,效果一样。
3. 单循环遍历
根据前面的思路分析,编写代码如下:
核心代码比较简单,注意除法运算需要使用整除,这样得到的才是整数。
至此,整个程序就全部完成了,你也可以输入不同的数字来测试效果啦
四.总结与思考
本题代码在10行左右,涉及到的知识点包括:
-
循环语句,主要是for...in;
-
条件语句;
-
输入处理;
-
列表的使用;
本题难度中等,要实现题目的要求不难,难的是如何找到最优的方法,提升代码的效率。
在上面给出的3种方案中,前面两种方案的时间复杂度都是O(n2)。相对来说,第二种方案效率要高一些,因为combinations()函数使用了一种优化的算法来生成组合,而不是简单地通过暴力枚举来尝试所有可能的组合。这种优化使得combinations()函数在处理大数据集时仍然能够保持较高的效率。
第三种方案的时间复杂度则为O(n),效率最高。当数据量较大的时候,这种优势会越来越明显。
所以,我们平常在编程的时候,不仅要能解决问题,还要进一步思考如何更好地解决问题,这样才能持续进步,更上一层楼。
超平老师给你留一道思考题,如果给出的数据有重复的,需要怎么处理呢?
顺便来一道经典的算法入门题,看看你能否解决:
给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值的那两个整数并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍,你可以按任意顺序返回答案。
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
你还有什么好的想法和创意吗,也非常欢迎和超平老师分享探讨。
如果你觉得文章对你有帮助,别忘了点赞和转发,予人玫瑰,手有余香😄
需要源码的,可以移步至“超平的编程课”gzh。