[导读]:超平老师的Scratch蓝桥杯真题解读系列在推出之后,受到了广大老师和家长的好评,非常感谢各位的认可和厚爱。作为回馈,超平老师计划推出《Python**蓝桥杯真题解析100讲》,**这是解读系列的第54讲。
**正整数分解,**本题是2020年12月20日举办的第12届蓝桥杯青少组Python编程省赛真题,第12届一共有两场省赛,这是第一场。题目要求将输入的正整数N分解成3个各不相同的正整数,并且不包含数字2和4。
先来看看题目的要求吧。
一.题目说明
编程实现:
输入一个正整数N(10 < N < 1000),然后将N分解成3个各不相同的正整数,即3个正整数之和为N。且要求每个正整数中都不包含数字2和4,输出一共有多少种不同的分解方法。
例如:输入的正整数N为12
将12分解为3个不同的正整数,且每个正整数都不包含数字2和4为:1,3,8和1,5,6。一共有两种分解方法。
注意:数字相同顺序不同的算一种分解方法。
输入描述:
输入一个正整数N(10 < N < 1000)
输出描述:
输出一共有多少种不同的分解方法
样例输入:
12
样例输出:
2
二.思路分析
这是一道排列组合题,考查的知识点主要包括循环、条件、字符串运算和枚举算法。
针对组合问题,在Python编程中一般有如下两种解决方案
-
枚举算法
-
使用combinations()组合函数
先来讨论枚举算法的实现方案,为了方便理解,我们通过两个实例来演示枚举的过程。
先以数字N = 12为例,将12拆分成3个互不相同的正整数,以1开头的有4种,如下:
1, 2, 91, 3, 81, 4, 71, 5, 6
以2开头的有2种,如下:
2, 3, 72, 4, 6
以3开头的有1种,如下:
3, 4, 5
再以数字N = 18为例,将18拆分成3个互不相同的正整数,以1开头的有7种,如下:
1, 2, 151, 3, 141, 4, 131, 5, 121, 6, 111, 7, 101, 8, 9
以2开头的有5种,如下:
2, 3, 132, 4, 122, 5, 112, 6, 102, 7, 9
以3开头的有4种,如下:
3, 4, 113, 5, 103, 6, 93, 7, 8
以4开头的有2种,如下:
4, 5, 94, 6, 8
以5开头的有1种,如下:
5, 6, 7
你发现这里的规律了吗?
如果用i、j、k来表示这3个正整数,可以发现如下3条规律:
1). i < j < k,因为(5, 6, 7)和(6, 5, 7)是相同的组合,只需要考虑前者就可以了;
2). i每次都是从1开始的,到 N // 3结束,这个也比较好理解,如果i,j,k三者相等,那么 i = j = k = N // 3,基于第一条规律,i的最大值也只能是N // 3;
3). j每次都是从 i + 1开始的,到 N // 2结束,这个怎么理解呢,因为j < k,取极端情况,i = 1,j = k,那么i + j + k = 1 + j + j = N,由此可知,j = (N - 1)// 2。
搞清楚这3条,就可以使用枚举算法,获取所有的组合,然后去掉包含数字2和4的组合。
第二种方案则是直接使用combinations()组合函数,相当于把枚举的活儿交给专业人士来干。
思路有了,接下来,我们就进入具体的编程实现环节。
三.编程实现
根据上面的思路分析,我们使用两种方案来编写程序:
-
枚举算法
-
组合函数
1. 枚举算法
根据前面的思路分析,我们编写代码如下:
代码不多,说明3点:
1). i和j的最大取值分别是 n // 3、n //2,由于range()函数虎头蛇尾的特点,需要加1;
2). 判断数字中是否包含2和4,最简单的方法就是使用字符串的in运算符,但是需要将整数转成字符串;
3). 对于k的取值,使用循环是可以的,但是直接利用 i + j + k = n的条件,可以省略循环,只需要确保 k > j,并且不包含数字2和4即可,这样可以极大地减少程序循环的次数,提升效率。
2. 组合函数
直接使用combinations()函数,编写代码如下:
代码比较简单,强调3点:
1). 要先导入combinations()函数;
2). combinations()函数的第一个参数是可迭代对象,这里使用range()函数生成了1到n之间的整数序列,这个范围也可以缩小到(n - 2),因为i最小值是1,j最小值为2;
3). combinations()函数返回的是元组,直接使用sum()函数对元组求和,同时过滤掉包含2和4的组合。
至此,整个程序就全部完成了,你可以输入不同的数字来测试效果啦
四.总结与思考
本题代码在12行左右,涉及到的知识点包括:
-
循环语句,尤其是嵌套循环;
-
条件语句;
-
字符串运算;
-
continue语句;
-
枚举算法;
这是本次省赛的第5题,难度中等。关键点有两个,一是如何获取所有的组合,二是如何过滤掉包含数字2和4的组合。
其中,对于组合的获取,在Python编程中,常见的方案就是循环枚举和组合函数。
对于枚举算法,需要根据实际情况来确定循环的层数,同时要对程序进行优化。包括两个方面,一是减少循环的层数,二是减少每一层循环的次数,从而提高程序的效率。
对于组合函数而言,这是Python给我们的小惊喜,尤其是combinations()和permutations()函数。真的是太好用了,能有就有,该用就用,可不要辜负了Python的一番美意。
超平老师给你留一道经典的算法入门题,看看你能否解决:
给你一个整数数组nums ,判断是否存在三元组[nums[i], nums[j], nums[k]]
满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为0且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
你还有什么好的想法和创意吗,也非常欢迎和超平老师分享探讨。
如果你觉得文章对你有帮助,别忘了点赞和转发,予人玫瑰,手有余香😄
需要源码的,可以移步至"超平的编程课"gzh。