質問

I have very recently started learning lisp. Like many others, I am trying my hand at Project Euler problems, however I am a bit stuck at Problem 14 : Longest Collatz Sequence.

This is what I have so far:

(defun collatz (x)
  (if (evenp x) 
      (/ x 2)
      (+ (* x 3) 1)))

(defun collatz-sequence (x)
  (let ((count 1))
    (loop
     (setq x (collatz x))
       (incf count)
       (when (= x 1)
     (return count)))))

(defun result ()
  (loop for i from 1 to 1000000 maximize (collatz-sequence i)))

This will correctly print the longest sequence (525) but not the number producing the longest sequence.

What I want is

result = maximum  [ (collatz-sequence n, n) | n <- [1..999999]]

translated into Common Lisp if possible.

役に立ちましたか?

解決 2

The LOOP variant is not that pretty:

(defun collatz-sequence (x)
  (1+ (loop for x1 = (collatz x) then (collatz x1)
            count 1
            until (= x1 1))))

(defun result ()
  (loop with max-i = 0 and max-x = 0
        for i from 1 to 1000000
        for x = (collatz-sequence i)
        when (> x max-x)
        do (setf max-i i max-x x)
        finally (return (values max-i max-x))))

他のヒント

With some help from macros and using iterate library, which allows you to extend its loop-like macro, you could do something like the below:

(defun collatz (x)
  (if (evenp x) (floor x 2) (1+ (* x 3))))

(defun collatz-path (x)
  (1+ (iter:iter (iter:counting (setq x (collatz x))) (iter:until (= x 1)))))

(defmacro maximizing-for (maximized-expression into (cause result))
  (assert (eq 'into into) (into) "~S must be a symbol" into)
  `(progn
     (iter:with ,result = 0)
     (iter:reducing ,maximized-expression by
      (lambda (so-far candidate)
        (if (> candidate so-far)
            (progn (setf ,result i) candidate) so-far)) into ,cause)))

(defun euler-14 ()
  (iter:iter
    (iter:for i from 1000000 downto 1)
    (maximizing-for (collatz-path i) into (path result))
    (iter:finally (return (values result path)))))

(Presented without claim of generality. :))

A late answer but a 'pretty' one, albeit a losing one:

(defun collatz-sequence (x)
  (labels ((collatz (x)
             (if (evenp x)
                 (/ x 2)
                 (+ (* 3 x) 1))))
    (recurse scan ((i x) (len 1) (peak 1) (seq '(1)))
      (if (= i 1)
          (values len peak (reverse seq))
          (scan (collatz i) (+ len 1) (max i peak) (cons i seq))))))

(defun collatz-check (n)
  (recurse look ((i 1) (li 1) (llen 1))
    (if (> i n)
        (values li llen)
        (multiple-value-bind (len peak seq)
            (collatz-sequence i)
          (if (> len llen)
              (look (+ i 1) i  len)
              (look (+ i 1) li llen))))))

(defmacro recurse (name args &rest body)
  `(labels ((,name ,(mapcar #'car args) ,@body))
     (,name ,@(mapcar #'cadr args))))
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top