【2019/08/1】Python作业

0:环境

  Python3.6.5

  JetBrains PyCharm 2018.1.4 x64

1、有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?

  为了能够不局限与该题题目限制,可以支持任意长数字和任意无重复的N位数,决定用递归解法来解决,而不是N次for(虽说递归很有可能炸不过这种题一般不会到达那么深的递归调用层数)

  基础思路是首先定义一个集合set,在集合内存放已经使用的数,每层递归用推导式新建未使用数的列表,遍历列表,在进入下一层递归之前将本层使用的数添加到set内,出来的时候再移除

    以下是我的代码

 1 def f_第一题(p_列表,p_n):
 2     """
 3         有四个数字:1、2、3、4,能组成多少个互不相同且无重复数字的三位数?各是多少?
 4         这里扩展为有不定个数组,能组成多少无重复的N位数
 5     :param p_列表:需要遍历的列表,可以拓展到m个数
 6     :param p_n:需要组成N位数
 7     :return:返回不重复数字次数
 8     """
 9     v_使用数字 = set()  #使用过的数字,初始为空
10     v_次数 = 0    #统计数量
11     #   使用了‘伪’闭包,我们没有返回一个函数,只是为了能让内部函数捕捉到外部函数内的变量
12     def f_第一题_递归(p_列表, p_层数, p_n,p_值):
13         """
14             用来确认每位数应该是什么
15         :param p_列表: 需要遍历的元列表
16         :param p_层数: 当前层数
17         :param p_n: 需要到达的N位数
18         :param p_值: 当前数字值
19         :return: 无返回值
20         """
21         if p_层数<p_n:    #如果层数还没超过N位数就继续遍历执行
22             t_数列 = [i for i in p_列表 if i not in v_使用数字] #从p_列表中取数并且不在set内的数来组成列表序列,都是未使用过的数字序列
23             for i in t_数列:
24                 v_使用数字.add(i)   #执行到这里就意味着要使用数字,所以添加到set集合内
25                 f_第一题_递归(p_列表,p_层数+1,p_n,p_值*10+i)  #开始下一层递归集合,数字因为是十进制数所以*10+i
26                 v_使用数字.remove(i)    #退出来了代表这位数之后的所有情况都已经遍历完毕,所以从set列表里移除
27         else:
28             print(p_值,end = " ")
29             nonlocal v_次数   #为了能够在内部函数里修改不可变数据类型需要指定为nonlocal
30             v_次数 += 1
31         pass
32     f_第一题_递归(p_列表,0,3,0)    #执行函数
33     print()
34     return v_次数
35     pass

2、利用递归函数调用方式,将所输入的5个字符,以相反顺序打印出来。

  我默认外部已经确认好了输入的字符,然后递归时用一个变量level来统计层数,判断是否超过*argv的长度来决定是否终止

    以下是我的代码

 1 def f_第二题(*argv,level = 0):
 2     """
 3         利用递归函数调用方式,将所输入的5个字符,以相反顺序打印出来。
 4         这里扩展为输入N个字符
 5     :param argv:输入的字符或其他东西
 6     :param level:当前层数
 7     :return:无返回值
 8     """
 9     if level < len(argv) :#当层数小于argv长度时就打印
10         print(argv[4-level],end="")
11         f_第二题(*argv,level = level+1)#到下一层时层数+1
12     pass

3、求100之内的素数。

  这题其实没必要用过滤函数……但是为了应用一下刚刚所学知识所以用上了

  主部分变量2到100(因为知道1不是)

  然后过滤函数判断是不是素数,判断变量2到根号x之间的数,如果有能够被整除的就说明不是素数,完全没有的话返回True

 1 def f_过滤函数(x):
 2     """
 3         判断数x是不是素数
 4     :param x:
 5     :return:
 6     """
 7     for i in range(2,int(math.sqrt(x)+1)):#变量2到根号x
 8         if not x%i:#如果取模为0代表能够被整除,就返回False
 9             return False
10     return True
11 
12 def f_第三题():
13     """
14         3、求100之内的素数。
15     :return:无返回值
16     """
17     v_iter = filter(f_过滤函数,range(2,101))#过滤函数返回的是迭代器
18     for it in v_iter:#遍历迭代器打印
19         print(it,end = "	")
20     print()
21     pass

4、有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。

  这题我也做了扩展,扩展到了 N个人围成一圈报到M的人退出

  这道题其实最正规的做法是用循环列表,但是python里貌似没有这个数据结构,再重新写好麻烦啊,所以就没用

  为了模拟,我用下标的变动来代替循环列表的变动

  一开始假设第一个人是1,然后第一个人序号是0,注意这里0是指向第一个人,而不是第一个人的前一个,所以第m个人退出的位置是0+m-1

  然后第m个人退出的时候,由于m位置空缺,此时下标没有指向下一个喊1的人的前一个,下标向前移动了指向了下一个喊1的人的位置,这样一来我们发现这和初始情况一样了!我们也将同样+m-1而不是m,每次+的时候为了防止下标不正确我们要对加的数取模,取当前列表长度的模

  比如说

  一开始有7个人,从1到3报数

  初始为

[ 1, 2, 3, 4, 5, 6, 7]

  1:第一步

  此时下标为0,0位置处说1,那么2位置处应该说3,根据我们的理论来看应该是(0+3-1)%len(列表)==2%7==2处位置,符合

  所以我们把2位置处的值3剔除

[ 1, 2, 4, 5, 6, 7]

  2:第二步

  此时下标为2,如果不删除3的话,2位置处应该是下一个说1的人的前面,但是因为删了,所以下一个人就向前移动了一位,所以此时指向了说一的人的位置,和初始情况一致。

  正常应该是下标为4的5号人说3剔除,根据我们的理论来看是(2+3-1)%len(列表)==4%6==4处,和推导的一致,符合

  所以我们把4处的值6剔除

[ 1, 2, 4, 5, 7]

  3:第三步

  此时下标为4,原理和上面一样,下一个说1的数向前移动了一格,序号7的人说1,所以应该是序号2的人说3,我们理论上看是(4+3-1)%len(数组)==6%5==1

  序号2的人的下标为1,和推导一致,符合

[ 1, 4, 5, 7]

  4:第四步

  此时下标为1,同上,序号4说的1,所以序号7的人应该剔除,理论是(1+3-1)%len(数组)==3%4==3

  序号7的人的下标为3,符合

  

[ 1, 4, 5]

  5:第五步

  此时下标为3,虽说越界了但是到时候取模肯定不会越界。同上,序号1的人说1,所以序号5的人应该剔除,理论是(3+3-1)%len(数组)==5%3==2

  序号为5的人的下标为2,符合

[ 1 ,4]

  6:第六步

  此时下标为2,序号为1的人说1,4说2,然后1再说3,所以序号为1的人剔除,理论上是(2+3-1)%len(数组)==4%2==0

  序号为1的人的下标为0,符合

[4]

  7:最后一步

  结果出现,结果为4

    以下是我的代码

 1 def f_第四题_生成器(n,m):
 2     """
 3         每次返回一个被剔除的数
 4     :param n: N个人
 5     :param m: M报数
 6     :return: 返回被剔除的人的值
 7     """
 8     v_序列 = list(range(1,n+1))#初始化1到N的人
 9     v_下标 = 0#初始化下标
10     while len(v_序列) > 0:
11         v_下标 = (v_下标 + m - 1)%len(v_序列)#为什么这么写博客上有解释
12         yield v_序列.pop(v_下标)#剔除对应的值并返回
13 
14 def f_第四题(n,m):
15     """
16         4、有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。
17         这里扩展为从1到m报数,报到m的人出去
18     :param n:N个人
19     :param m:报数到m
20     :return:无返回值
21     """
22     v_iter = f_第四题_生成器(n,m)#生成器生成下一个被剔除的数
23     v_结果 = 0
24     for it in v_iter:#遍历每次的剔除的数结果
25         v_结果 = it
26     print(v_结果)#最后一个被剔除的就是结果

  5、使用装饰器是实现性能测试,在每次调用某个函数的时候,都要计算一下被调用的函数所消耗的时间

  很简单的装饰器应用……具体装饰器定义百度吧……

    以下是我的代码

 1 import time
 2 def f_装饰器(p_被测试函数):
 3     #   为了支持任何函数所以定义成这种形式以封包参数
 4     def f_测试(*argv,**kw):
 5         v_开始时间 = time.time()#   开始记录开始时间
 6         p_被测试函数(*argv,**kw)#    执行函数
 7         v_结束时间 = time.time()#   记录结束时间
 8         print("函数{0}的执行时间为:{1}".format(p_被测试函数.__name__,v_结束时间-v_开始时间))#    打印函数名和执行时间,执行时间是结束时间-开始时间
 9     return f_测试#装饰器返回被测试函数
10 
11 #   在被测试的函数前用@装饰器名修饰,有参数的话加上参数
12 @f_装饰器
13 def f_被测试函数1(a,b,c):
14     print(a,b,c)
15     time.sleep(0.6)

  


  以上皆为自己所思,转载请注明出处

原文地址:https://www.cnblogs.com/dofstar/p/11293961.html