继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

【Python初级】由生成杨辉三角代码所思考的一些问题

回首忆惘然
关注TA
已关注
手记 333
粉丝 73
获赞 413

杨辉三角定义如下:

          1
         / \
        1   1
       / \ / \
      1   2   1
     / \ / \ / \
    1   3   3   1
   / \ / \ / \ / \
  1   4   6   4   1
 / \ / \ / \ / \ / \
1   5   10  10  5   1

把每一行看做一个list,试写一个generator,不断输出下一行的list。

该题目考查生成器的应用。一般的思路是,首先在每一行输出一个1,随后通过循环,位置i(从2开始)的数是上一行i与i-1位置的数之和,当i与上一行数字个数相同时,循环终止,最后再添加进一个1,形成新的一行。

基于这个基本思路,将python的生成器运用到里面,有两种常见的写法:

一种写法如下:

复制代码

1 def triangles():#杨辉三角的一种生成方法2     l = [1]3     while True : 
4          yield l5          for i in range ( 1,len (l) ) :6              l [i] =  h [i] + h [i-1] 
7          l.append (1)8          h = l[:]

复制代码

另外一种写法如下,运用了list的生成式:

1 def triangles():2     l = [1]    
3     while True :4        yield l5        l = [1] + [ l[i] + l[i+1] for i in range ( len (l) - 1)] + [1]

可以看到,以上两种写法都是相当简洁的。一开始这两个代码看不太懂,比如说为啥第一种写法里一开始h里面没有数,却也能够正常执行?主要是对于生成器的yield机制不明白,以及对于range的用法不是特别清楚。以下就这两点分别解释。

首先,当函数中出现了yield之后,该函数就不再被视为函数,而视为一个生成器。此时,整个函数被使用的语句流程会发生改变,一般的函数都是调用的时候从函数入口进,发现return或函数执行完毕后返回,而生成器函数则是每次调用函数执行,执行到yield返回,下次再调用函数的时候从上次yield返回处继续执行。

其次,range的用法中是,如果是【range(x,x) 其中x是常量】的形式,range依然返回空。故在上述代码的for循环中,由于在第一次试图循环的时候,后面的range要么是range(1,1)要么是range(0),故都会成功避开i或者h没有实际值的循环,执行接下来的部分。当第二次试图循环开始时,i和h内的内容都已经满足条件了,所以就能正常运行了。

还有一种我看到的最简单的写法:

1 def triangles():2     L = [1]3     while True:4         yield L5         L= [(L + [0])[i] + ([0] + L)[i] for i in range(len(L)+1)]

这一种写法直接去掉了第二种写法里每次L两边额外插入的[1],使其变为了一个完整的一个list生成式,可以说是相当精妙。

那么,这种写法为什么也可以呢?我们再来分析一下杨辉三角的性质,这样,为了直观理解,我们先利用上面的代码,举一个运行中的过程例子。

比如,L此时为[1,1](杨辉三角第二行),现在需要求第三行。根据第五行的生成式,将按照以下步骤进行计算:

1.L尾部加0,得到[1,1,0],我们称之为tempL1

2.L首部加0,得到[0,1,1],我们称之为tempL2

3.现在,根据之后的for循环,L最终要被赋值成由tempL1与tempL2对应的每个相同位置数字之和所组成的列表,经过计算,这个新的L应该为[1,2,1]。居然确实是杨辉三角的第三行!

相信聪明的观众已经明白了,这个最简单的写法是利用了杨辉三角本身的对称性质,让同一行错开一位竖式相加,得到的就是下一行的结果。同时,利用python里面本身就极为方便的列表扩展写法和列表生成式,才有了第三种如此简洁的写法~

原文出处

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP