【发布时间】:2021-12-21 01:43:56
【问题描述】:
我用下面的代码解决了Sum by Factors:
#lang racket
(provide sum-of-divided)
(define (sum-of-divided lst)
(define (go ps n l)
(define ((exhaust d) x)
(define q (/ x d))
(if (integer? q)
((exhaust d) q)
(if (> x 1) `(,x) '())))
(if (null? l)
ps
(if
(for/or
([p ps])
#:break (< n (sqr p))
(= 0 (modulo n p)))
(go ps (+ n 1) l)
(go
(append ps `(,n))
(+ n 1)
(append-map (exhaust n) l)))))
(for*/list
([m (go '() 2 (map abs lst))]
[s `(,(for/fold
([a '(0 #f)])
([x lst])
(if (= 0 (modulo x m))
`(,(+ (car a) x) #t)
a)))]
#:when (cadr s))
`(,m ,(car s))))
令我惊讶的是,在我将 L20 中的 sequence-append 更改为 append 之后,它才通过了时间限制为 12 秒的测试。 documentation for sequence-append 说:
新序列是惰性构造的。
但是,事实证明,这显然意味着除非需要,否则不会连接后续序列。但是当需要它们的元素时,即由sequence-append 产生的序列被消耗得足够远,就会产生与所有先前序列的长度之和呈线性关系的时间成本。正确的?这就是它慢的原因吗?
如果是这样,如何解决它? (在这种情况下,append 的性能已经足够好了,但假设我真的需要一个结构,它至少是一个具有通常复杂性的 FIFO 队列。)在racket 语言中是否有一个很好的替代方案,没有requireing 额外的包(这可能不可用,就像 Codewars 上的情况一样)?差异列表可能(从头开始很容易实现)?
【问题讨论】:
-
我怀疑所有准引用/取消引用可能比使用“正常”列表构建功能要慢。
-
有趣的怀疑。我是认真的。为什么会这样?无论如何,这种情况下的关键区别是
append与sequence-append。
标签: performance queue concatenation racket lazy-evaluation