动态规划:O(N)
它已经提到,该问题通过使用帕斯卡三角形及其与二项式系数的关系有一个解决方案。Catalan number的条目也很好地说明了n × n的情况。
n × n例
通过利用上述资源,您可以得出结论,对于大小为n × n的网格,您需要计算 C(2n - 2, n - 1)。您可以通过将网格旋转 45 度并映射帕斯卡三角形来仔细检查它。
实际上,直接计算这个数字需要以一种幼稚的方式计算最多 3 个不同的阶乘,这是一项非常昂贵的任务。如果你可以预先计算它们,那么这里就没有讨论了,你可以说这个问题的复杂度为 O(1)。如果您对预先计算的方式不感兴趣,那么您可以继续阅读。
您可以使用动态规划 (DP) 来计算这样的不祥数字。这里的诀窍是以更小的步骤执行操作,这根本不需要您计算大的阶乘数。
也就是说,要计算 C(n, k),您可以先将自己置于 C(n, 1) 处,然后步行到 C(n, k)。让我们首先根据 C(n, k - 1) 定义 C(n, k)。
C(n, k) = n! / k! * ( n - k )! ; k! = (k - 1)! * k
= n! / (k - 1)! * k * (n - k)! ; (n - k)! = (n - k + 1)! / (n - k + 1)
= n! * (n - k + 1) / (k - 1)! * k * (n - k + 1)! ; C(n, k - 1) = n! / (k - 1)! * ( n - k + 1 )!
= C(n, k - 1) * (n - k + 1) / k
基于此,您可以在 Python 中定义一个计算 C(n, k) 的函数,如下所示:
def C(n, k):
"""
Calculate C(n, k) using Dynamic Programming.
C(n, k) = C(n, k - 1) * (n - k + 1) / k
"""
C = 1
for ki in range(1, k + 1):
C = C * (n - ki + 1) / ki
return C
它以线性时间运行,O(N)。
对于n × n情况,您需要计算 C(2n - 2, n - 1)。
>> print "Response: %dx%d = %d" % (n, n, C(2 * n - 2, n - 1),)
Response: 10000x10000 = 5...
n × m情况
对于一般的n × m情况,您只需要计算 C(n + m - 2, m - 1)。
>> print "Response: %dx%d = %d" % (n, m, C(n + m - 2, m - 1),)
Response: 10000x10000 = 5...
最后但并非最不重要的一点是,您可以在此处查看 Ideone 的实时示例。
计时
我针对以下网格大小运行了算法。
N x N | Response's Length | Time
-----------------+-------------------+-----------
1 x 1 | 1 chars | 0.000001
10 x 10 | 5 chars | 0.000004
100 x 100 | 59 chars | 0.000068
1000 x 1000 | 600 chars | 0.002207
10000 x 10000 | 6018 chars | 0.163647
100000 x 100000 | 60203 chars | 40.853971
由于涉及的数量非常多,似乎超过 100 000 x 100 000 网格大小的操作变得异常昂贵。不过没什么好惊讶的。