在学校,我一直在学习运行时和使用尾递归等编写更有效的算法,不久之后,一项任务要求我们考虑计算功能的函数;
(define (exp x n)
(if (zero? n) 1 (* x (exp x (- n 1)))))
我们的任务是编写一个带有运行时O(log n)的exp函数,所以这是我的答案:
(define (exp x n)
(cond
((zero? n) 1)
((= 1 n) x)
((even? n) (exp (* x x) (/ n 2)))
(else (* x (exp (* x x) (/ (- n 1) 2))))))
简单来自x ^ 2n =(x ^ 2)^ n和x ^ 2n + 1 = x *(x ^ 2)^ n。
所以我一直试图想出一种实现尾递归的方法来进一步优化这个功能,但我真的想不出办法做到这一点。回答我的问题,有什么排序rule of thumb
知道何时可以将多项式运行时算法编写为对数运行时?
我问这个问题,因为,就像它的运行时是对数的那样简单地编写它,我从来没有想到这样做而没有特别要求这样做。
答案 0 :(得分:3)
关于问题的第一部分:将过程转换为尾递归形式相对简单,我们只需要传递一个额外的参数来累积答案。为避免创建其他程序,我将使用named let
:
(define (exp x n)
(let loop ([x x] [n n] [acc 1])
(cond
((zero? n) acc)
((= n 1) (* x acc))
((even? n) (loop (* x x) (/ n 2) acc))
(else (loop (* x x) (/ (- n 1) 2) (* x acc))))))
对于第二个问题:经验法则是 - 如果有一种方法可以在进行递归调用时以某种方式将问题的大小减半(以这种方式可以相应地计算结果),那么这是一个很好的迹象,它可能存在一个对数解决方案。当然,这并不总是那么明显。