Abaixo está minha tentativa, no esquema R5RS (isenção de responsabilidade: eu ainda não sou um Schemer (ainda!), Portanto, perdoe o (provavelmente) terrível código).
(define count 10)
; `factors` is our vector of linked-lists of factors. We're adding to these
; as we go on.
(define factors (make-vector count 'not-found))
(vector-set! factors 0 '())
; `primes-so-far` contains all the prime numbers we've discovered thus far.
; We use this list to speed up the dividing of numbers.
; `primes-so-far-last` is a ref to the last entry in the `primes-so-far`
; list, for O(1) appending to the list.
(define primes-so-far '(dummy))
(define primes-so-far-last primes-so-far)
;; Helpers
(define (factor-ref n)
(vector-ref factors (- n 1)))
(define (factor-cached? n)
(not (eq? (vector-ref factors (- n 1)) 'not-found)))
(define (factor-put n factor)
(let* ((rest (/ n factor))
(factor-cell (cons factor (factor-ref rest))))
(vector-set! factors (- n 1) factor-cell)
factor-cell))
(define (prime-append n)
(let ((new-prime-cell (cons n '())))
(set-cdr! primes-so-far-last new-prime-cell)
(set! primes-so-far-last new-prime-cell)
new-prime-cell))
;; The factor procedure (assumes that `[1..n-1]` have already been factorized).
(define (factor n)
(define (divides? m n)
(= (modulo n m) 0))
; n the number to factor.
; primes the list of primes to try to divide with.
(define (iter n primes)
(cond ((factor-cached? n)
(factor-ref n))
((null? primes)
; no primes left to divide with; n is prime.
(prime-append n)
(factor-put n n)) ; the only prime factor in a prime is itself
((divides? (car primes) n)
(factor-put n (car primes))
(factor-ref n))
(else
(iter n (cdr primes)))))
(iter n (cdr primes-so-far)))
(define (print-loop i)
(if (<= i count)
(begin
(display i)
(display ": ")
(display (factor i))
(newline)
(print-loop (+ i 1)))))
(print-loop 1)
Imprime como:
1: ()
2: (2)
3: (3)
4: (2 2)
5: (5)
6: (2 3)
7: (7)
8: (2 2 2)
9: (3 3)
10: (2 5)
(Não exatamente como na descrição da tarefa, mas tudo o que você precisa fazer para obter essa saída é dobrar a lista e mesclar repetições do mesmo número, durante a parte de saída do código. A representação / algoritmo interno ainda seria o mesmo.)
A idéia é armazenar em cache os valores calculados anteriormente, mas faça uso do fato de que os fatores de n
são o primeiro fator principal de n
e os fatores primos de (n / primeiro fator). Mas o último já é conhecido, então apenas reutilizamos a lista de fatores já existente para esse número menor. Assim, para cada número [1..n]
que não é primo, uma única célula de contras é armazenada.
Para cada número, uma única célula de contras é criada e armazenada. Portanto, essa abordagem deve ser executada com O(n)
o uso do armazenamento. Não tenho idéia se é possível expressar com precisão a complexidade do tempo.