许多Project Euler问题都需要在 base10 和 base2 中处理整数及其数字。虽然我在转换数字列表中的整数或将 base10 转换为 base2(或它们的数字列表)方面没有问题,但我经常发现重复进行此类转换时性能很差。
这是一个例子:
首先,这是我的典型转换:
#lang racket
(define (10->bin num)
(define (10->bin-help num count)
(define sq
(expt 2 count))
(cond
[(zero? count) (list num)]
[else (cons (quotient num sq) (10->bin-help (remainder num sq) (sub1 count)))]
)
)
(member 1 (10->bin-help num 19)))
(define (integer->lon int)
(cond
[(zero? int) empty]
[else (append (integer->lon (quotient int 10)) (list (remainder int 10)))]
)
)
接下来,我需要一个函数来测试一个数字列表是否是回文
(define (is-palindrome? lon)
(equal? lon (reverse lon)))
最后,我需要将低于某个最大值的所有 base10 整数相加,这些整数是 base2 和 base10 中的回文数。这是累加器样式的函数:
(define (sum-them max)
(define (sum-acc count acc)
(define base10
(integer->lon count))
(define base2
(10->bin count))
(cond
[(= count max) acc]
[(and
(is-palindrome? base10)
(is-palindrome? base2))
(sum-acc (add1 count) (+ acc count))]
[else (sum-acc (add1 count) acc)]))
(sum-acc 1 0))
和常规递归版本:
(define (sum-them* max)
(define base10
(integer->lon max))
(define base2
(10->bin max))
(cond
[(zero? max) 0]
[(and
(is-palindrome? base10)
(is-palindrome? base2))
(+ (sum-them* (sub1 max)) max)]
[else (sum-them* (sub1 max))]
)
)
当我将最后两个函数中的任何一个应用于 1000000 时,我需要 10 多秒才能完成。递归版本似乎比累加器版本快一点,但差异可以忽略不计。
有什么办法可以改进这段代码,还是我只需要接受这是 Racket 并不特别适合的数字运算风格?
到目前为止,我已经考虑过用类似的 integer->vector 替换 integer->lon 的可能性,因为我希望 vector-append 比 append 更快,但是我坚持需要稍后应用 reverse。