也许我的回答与递归无关,而且这个问题与 @Sylwester 的回答完全不同,但展示解决此问题的另一种方法仍然很有用。
假设帕斯卡三角形具有以下性质:
- 帕斯卡三角形每一行的第一项和最后一项都是'1'
- 第二个也是倒数第二个是行数
-
任何其他元素都可以通过公式解决:
这意味着,您可以通过时间复杂度 O(n^3) 的线性算法求解帕斯卡三角形的任何元素。它可能并不比具有 O(n^2) 和递归的递归版本酷,但它不会破坏堆栈并且它使用组合,在我看来这更好,因为它更简单和更安全的版本。
所以,我们开始吧:
(defn naive-factorial[n]
(reduce *' (range 1 (inc n))))
(defn combinatoric-formula[line pos]
(if (<= pos line)
(/
(naive-factorial line)
(*' (naive-factorial pos)
(naive-factorial (- line pos))))))
如您所见,使用了 naive-factorial 函数,该函数采用 n 乘法,导致我们得到 O(n^3)。它与您的函数相同,但没有任何递归。
对于帕斯卡三角形,也有不止一种方法可以用不同的方式解决它们。有的很刁钻,有空的可以看看:rosettacode.org
此外,在您使用 + 在 clojure 中使用 int 数学的版本中,请在任何可能导致大量数字的情况下使用 +' 函数(假设这意味着添加将导致转换您的值到 biginteger 类型,这允许非常大的数字)。
我还将 @Sylwester 介绍的方案版本翻译成 clojure:
(defn pascal [row col]
(let [aux
(fn aux [tr tc prev acc]
(cond (> tr row) (throw (.Exception "invalid input"))
(and (= col tc) (= row tr)) (+' (first prev) (second prev)); the next number is the answer
(= tc tr) (recur (+' tr 1) 1 (cons 1 acc) '(1)) ; new row
:else (recur tr ; new column
(+' tc 1)
(next prev)
(cons (+' (first prev) (second prev)) acc))))]
(if (or (zero? col) (= col row))
1
(aux 2 1 '(1 1) '(1)))))
它也许可以改进,但显示了这个想法。它计算了从第三行到上一个提供的输入的整个三角形,然后得到答案。功能方法非常棒和纯粹的魔力。
这个版本的性能比线性版本差很多。
所以它得到:
(time (combinatoric-formula 1000 100))
"Elapsed time: 2.73794 msecs" for linear version
(time (pascal 1000 100))
"Elapsed time: 135.426888 msecs" for tail recursion version
但它仍然更清洁和凉爽;)