杨辉三角形生成器

  《程序员的数学》通过“杨辉三角形”(Pascal’s Triangle)的演示了一种“从复杂问题中发现隐含递归结构”的方法:1)从整体中隐去部分问题;2)判断剩余部分是否和整体问题是同类问题。通过这种方法可以很好的解释“为什么杨辉三角形中会出现组合数”。
  《程序员的数学》只是揭开了“杨辉三角形”神秘的一角:相邻两数之和、阶乘、路径选择、组合数。除了这些,MathisFun - Pascal’s Triangle 中介绍了很多它的神奇关联,有兴趣的可以去看看。不过,本文的重点是:如何通过简单的代码来生成“杨辉三角形”。

注:事实上,我在中学阶段就接触到了“杨辉三角形”,最早接触的 二项式定理 ( a + b ) n 就与杨辉三角形紧密的联系在一起。
  

一、杨辉三角形

  在此我借用《程序员的数学》中的方法来表示“杨辉三角形”,第一种表示法是传统的“相邻两数相加”。
        这里写图片描述

  如上图所示,每个数字都是上方与它相邻的两数之和,其中箭头表示两数的相加方向。下面是一个动图
                这里写图片描述

  另一种表示“杨辉三角形”的方法——组合数,如下:
            这里写图片描述

  事实上,借助“杨辉三角形”运用拓扑学中 “路径选择” 能够帮助我们轻松理解组合数 C n k 以及递推公式 C n k = C n 1 k 1 + C n 1 k
            这里写图片描述

  如上图所示,思考一下从起点到终点共有多少中走法(路径选择)?而各个分叉点标注的正好是从起点到本分叉点的走法。再看下面这个图:
          这里写图片描述

  从起点到终点,或左或右走下来的路线有多少呢?总共要进行5次选择,其中不管怎么选,上图要到达终点,必须不多不少的选择3次往右。

C 5 3 = 5 ! ( 5 3 ) ! 3 ! = 10

  这个就是组合数的意义。
          这里写图片描述

  

二、杨辉三角生成器

  杨辉三角形的最基本定义是“相邻两数相加”,但是,三角形两边的数并不是相加得到的,因此在用代码表示的时候,会增加 if-case 分支。我想到了一种方法,通过在每行两端补,来达到统一,代码如下:

# -*- coding: utf-8 -*-

def triangles():
    lst = [1]
    yield lst
    while True:
        lst1 = [0] + lst
        lst2 = lst + [0]
        lst = []
        for v1, v2 in zip(lst1, lst2):
            lst.append(v1+v2)
        yield lst

  这段代码非常好理解,就是将原向量复制成两份,在首尾补零,然后就是两个向量相加生成新的向量。但是,从算法的复杂度上来说,空间复杂度有点高—— O(3n)。下面再给出一个优化版本:

# -*- coding: utf-8 -*-

def triangles():
    lst = [1]
    yield lst
    while True:
        prev = 0
        lst = lst + [0]
        for i in range(len(lst)):
            tmp = lst[i]
            lst[i] += prev
            prev = tmp
        yield lst

  分析:从渐进意义来说,这两个版本的复杂度是一样的。
  

三、扩展

  除了“杨辉三角形”,还有一个非常经典的组合数列——卡特兰数(Catalan Numbers),它在数学竞赛、信息学竞赛、组合数学、计算机编程等方面都会有其不同侧面的介绍,比如:卡特兰数——计数的映射方法。它的Python生成代码如下:

# A recursive function to find nth catalan number
def catalan(n):
    # Base Case
    if n <=1 :
        return 1

    # Catalan(n) is the sum of catalan(i)*catalan(n-i-1)
    res = 0
    for i in range(n):
        res += catalan(i) * catalan(n-i-1)

    return res

# Driver Program to test above function
for i in range(10):
    print catalan(i),
# This code is contributed by Nikhil Kumar Singh (nickzuck_007)

注:以上代码出自 program nth catalan number
  

猜你喜欢

转载自blog.csdn.net/sagittarius_warrior/article/details/79258082