Python习题集

【习题】

1汉诺塔的移动

2自定义strip方法

3打印前n个斐波那契数列的值

4打印杨辉三角

5使用reducemap重新定义函数float( )

6打印所有素数

7L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]排序

8设计一个decorator,使它能作用于任何函数,并打印出函数执行的时间

9将题【8】中的装饰器作用于一个打印素数的函数,要求输入素数的最大值

10将题目改造成class

11让用户输入名字,再次运行程序后仍可对用户表示欢迎(并确定用户是否为上次运行该程序的用户)

 

 

 

【课外练习】

1定义阶乘函数

2记由1234组成的三位数为x,写出所有无重复数字的x

3一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?

也就是,x为整数,n1,n2也为整数

4打印九九乘法表

5101200之间的所有素数及个数

6将一个正整数分解质因数

7输入一个成绩,符合{'A': >= 90 'B': 60 <= x < 90'C': < 60 },分别输出等级

8一个数如果恰好等于它的因子之和则称为"完数"。例如6=123.编程找出1000以内的所有完数

9打印一个菱形图案

10利用递归,将输入的一个字符串倒序输出

11按逗号分隔列表,如L = [1,2,3,4,5],返回1,2,3,4,5

 

【零落的知识点】

sum( list ) = reduce( lambda x,y : x+y , list )

L[:1] = L[0]

num = 123num = input( )、输入123;这两者获得的123类型都为str,而不是int

④ 习题中有一题是比较输入的两个值,Maximum = lambda x,y : (x>y)*x + (x<y)*y,式子中的(x>y)(x<y)都是布尔表达式,当为True时显示为1、为False时显示0;将01代入式子中,恰好可以计算出最大值。(当然,存在x=y时的bug

⑤ 自定义int( )函数:return reduce( fn , list(map(int , n)))

⑥ 高阶函数可被简化:

map(add_10 , [1,2,3]) --> [add_10(i) for i in [1,2,3]]

reduce(lambda x: x > 5 , [1,2,8,5,9]) --> [x for x in [1,2,8,5,9] if x > 5]

 

【答案】

1汉诺塔的移动

 

PS:从抽象层面上去理解

2自定义strip方法

 

PS:从这题中可看出,对递归和切片的运用还很不熟练

3打印前n个斐波那契数列的值

方法①:

 

PS:利用同行赋值式,你应该记得上面的a , a+b被组装成一个排序

方法②:

 

PS:结合斐波那契数列的特性,先设立特殊情况【即前两个[1]】,再利用Python从后遍历,使用append

方法③:(输入x,若仅显示第x个数,而不是显示从1x的整段数列)

 

PS:理解斐波那契数列的特性,先设立特殊起始值,通过递归,在抽象层面上解决问题

方法④:(与方法③相似,都是运用递归,但可显示1x的整段数列)

 

PS:输入x,方法③只能显示第x个数值,如此,利用map遍历range(1,x+1)得到整个Iterator问题是它似乎占用很大内存,调用Fib20】有时会长时间无法计算出结果笔记{尾递归}中有问题的补充,原因是其递归算法造成极大的冗余调用,复杂度是指数级的

方法⑤:(这是对方法④的改进,解决递归的低效率问题)

 

PS:两者的Fib函数没有不同,但这里的fib函数其实是模仿方法①的同行赋值式a,b = b,a+b,设立特殊值(n = 1n = 2),设立算法的最终输出(n = 3时返回a+b,符合斐波那契数列的定义),通过递减n控制次数,在次数限制下不断对初始的a = 1 , b = 1进行逻辑运算,得到结果

由代码可看出,每到递归的步骤时仅对函数自身调用1次,由于n是递减的,所以这个函数的复杂度是线性的;由于Python默认限制最大递归深度为997,所以该代码可计算Fib(900)无压力

方法⑥:(非函数在模块中被导入,而是直接运行.py文件)

 

PS

这里最重要的一点是最后的print( )函数,作为函数的返回值返回后,在命令行窗口会直接输出;但运行.py文件却不会,即使返回一个list,也没有标明对它的操作是什么,因此这时借助print( )函数输出

此外,对高阶函数的运用还不到位,map都丢到角落不会用了,傻傻地1行代码写成4...

4打印杨辉三角

 

———————————————————————————————————————————————————

PS:思路有了,但对数值的把握火候不够,n的初始值总是要进过调试才能确定...不知道这是否正常

 

PS:渐渐开始熟悉了:

①假设列表L存在,由于规则为相邻两个数值相加,可通过range( len(L) -1 )来控制本次相加的次数

②通过max值来控制总的L的相加次数

5使用reducemap重新定义函数float( )

 

———————————————————————————————————————————————————

 

涉及字典dictlambdaindex

6打印所有素数

 

① 定义全体自然数N,用n = N( )获取Iterator

② 定义筛选函数not_division,注意这里的双变量使用(注:这里的filter中的函数可以接收参数)

n1 = next(n)获取Iterator的第一个值,返回第一个值后,用filter进行筛选,n中但凡是可以整除n1的都会被删去,包括与n1等值的n的第一个值。

④ 不断重复步骤③,不断获取第一个值

7L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]排序

 

PS:由于各个元素为tuple,匿名函数旨在单独取出各个tuple中的字符串或数字

8设计一个decorator,使它能作用于任何函数,并打印出函数执行的时间

 

PS:注意执行函数func需在定义startend之间;以及最后记得返回wrapper

记得语法糖@的含义,以及使用它时的位置

9将题【8】中的装饰器作用于一个打印素数的函数,要求输入素数的最大值

 

PS:①原primes为迭代器,要想被装饰,修改为函数(通过提前设立max、将yield改为print

②严格遵照了装饰器(Docorator)的模板

③采用if __name__ == '__main__'的方式减少繁杂的程序测试

10将斐波那契数列题目/打印素数题目修改为class

 

PS:通过input、初始化self.max可以达到设置退出循环条件的目的~

 

PS:这里锦上添花,运用了\rtime模块的sleep函数,效果不错,但是被注释掉的那行如果替代现在的print,(也就是我想输出一长列的元素,但每个稍有些间隔才出现),会发现无法退出循环【??】

11让用户输入名字,再次运行程序后仍可对用户表示欢迎(并确定用户是否为上次运行该程序的用户)

 

PS:多练习,这是经过重构的代码

【课外练习答案】

1定义阶乘函数

方法①:(使用高级函数)

 

方法②:(利用递归)

 

2记由1234组成的三位数为x,写出所有无重复数字的x

 

PS:思维局限在要打印一个完整的数字,殊不知可以将一个数字看成是多个数字字符串的并列组合

3一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?

,其中x为整数,n1,n2也为整数

 

PS:在草稿纸上列出数学关系式,即题目的第二行

①先找出n2的最大值:由于n1n2同为完全平方数,所以假设它们之间的间隔为最小值1,又已知它们平方后的间隔为168,所以通过while不断接近n2的近似最大值;通过求出n2的近似最大值,可以减少计算机的无效计算

②通过列表生成式将分别满足条件n1n2x筛选出来,设为x1x2,;由于n2为最大值,即n2 > n1n1的范围是n2的子集,所以所求的n2近似最大值可以作用于n1

③求出x1x2后,由于x1x2分别为一半题目的解,这时题意就变为求同时满足x1x2x的所有可能;通过set( )list转变为无序且不重复的集合,再将set进行数学的集合运算,即求交集,得到答案x

最后,上述列表生成式可以用高阶函数maplambda取代:

 

4打印九九乘法表

 

PS:其中涉及print函数中的end用法,详见参考笔记O(_)O

5101200之间的所有素数及个数

首先这是一个错误的范例:

 

调试结果表明,如果连续出现3个合数,如104,105,106,上述方法会将中间的105忽略!

原因:Pythonfor循环是根据下标的,上述方法中,当remove(104)后,原本{104}所属的索引位4被空缺,接由后面的{105}取代索引位4break后,for循环依据下标,直接对索引位为5的元素进行逻辑运算,就这样,索引位为4{105}被错过;事实上,当{102}remove掉,后面的{103}也没有被检测,尽管{103}是素数,但这种筛选方法显然是有漏洞的

正确范例:

 

修改后的代码对L使用了切片复制得到L_copy,在判断时使用的是L中的元素,但删除的却是L_copy中的元素,这样,for循环迭代L中元素时不会出现遗漏

方法②:(待删)

 

PS:我之前就疑惑如何完全删除一个数列中所有的某个元素,直到复习时无意发现结合使用whilein可以重复删去,这才成功;然后就是定点删除的问题,list没有remove这个属性,属于检测到x为合数时,没办法直接删去x,所以只能使用手动下标,将合数先转变为空格,再将list中的所有空格删去

6将一个正整数分解质因数

 

PS:该题较为简单,复习时可尝试使用range;有人先用生成器生成一个素数的无限数列,然后将参数n逐个除以素数,并输出该素数和修改参数n

7输入一个成绩,符合{'A': >= 90 'B': 60 <= x < 90'C': < 60 },分别输出等级

 

PS:这是一种暂时还没学的方法,该方法在Python 3.x上运行是ok的,从代码的内容和运行情况可以大致了解一下这种方法。

①格式为print([...][...])

②前一个[...]中输入若干个字符串,字符串按顺序排列,拥有索引012

③后一个[...]对输入的参数进行判别且必须进行参数运算,单纯地[score]会报ValueError,所以哪怕是无意义的[score//1]也必须敲上;对参数进行运算后(即上述的score//30),根据得到的结果分别对应索引号输出相应的字符串,若无对应的索引号,将会报IndexError

以上面代码为例,前一个[...]共有4个字符串等待输出,则拥有4个索引号,即0123;又因为后面的运算为[score//30],要想参数score地板除30得到相应的索引号,则score的范围为[0,120];又由于Python支持倒数遍历,所以索引号-1-2-3-4都是允许的,所以参数score范围实为[-120,120],超出范围即报IndexError

在符合范围的前提下,每运算出一个一个相应的索引号,就会print相应的字符串

8一个数如果恰好等于它的因子之和则称为"完数"。例如6=123.编程找出1000以内的所有完数。

 

PS:不难,待删

9打印一个菱形图案

效果图:

PS1:我原本的思路是根据max得到L = '  '*max,算出max中间那个数middle,定义逐渐递增的num,使范围在(middle - num , middle + num)中的所有空格替换成星号'*';问题是字符串在Python中是不可修改的,修改的方法

replace,这个方法中如替代L[0]L[0].upper( ),所有为L[0]的字符都会被替换,而不只是L[0]处的字符

join,似乎可行,但还没学   【所以以后学了试试?】

③切片,字符串也是序列,可以使用序列下标的方式,即L[:3]+'*'*num+L[-3:]

惊觉方法③有可能成功,然后马上试验:

 

PS2:这里有几点说明下:

①改善了原问题,使规定打印星号{*}的菱形变为打印输入的某个字符,即用string替代 '*'

num -= 4的原因在图中有说明

③实际上,L[:l_num] + string*num + L[r_num:]中的数据没有经过准确推敲,而是凭感觉敲上去的

④若输入的string为中文汉字,由于汉字所占的字节数为2,而空格为1,所以不能形成规则菱形

这里的类型检查似乎不行,if not ( isinstance ( string , str ) ) or ( isinstance ( max , int ))  已解决,应if not ( isinstance ( string , str ) ) and ( isinstance ( max , int ))andor使用错误

 

PS3:我是认定每一行长度皆为max,在这个基础上敲代码;另一种思路是只看每行星号前的空格数、星号数,星号后面的就由它去吧。上面的代码就是一个例子

【标准答案涉及stdout

10利用递归,将输入的一个字符串倒序输出

 

PS:递归时注意len(n)这个数就比n最后一个字符的索引大1,所以即使切片[x:y]不取y,也要减去1

   【打印出的每个字符都间隔一个空格,尝试将空格删除?】

11按逗号分隔列表,如L = [1,2,3,4,5],返回1,2,3,4,5

 

PS:这题旨在剥除list的外壳,将里面的元素逐个返回,关键点在于打印逗号,可用[1:-1]去除首端的空格和末尾的逗号

 

PS:同样可通过print来实现,注意ifelse的位置,且之间无需其他分隔符

【此外,有的答案还涉及joinrepr

 

posted on 2019-05-26 13:12 刻意 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/I-am-not-happy/p/10925752.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值