计算n位回文无限循环

时间:2018-03-20 04:56:37

标签: math recursion racket

我正在尝试使用Racket和Project Euler作为练习的参考。这个问题与问题4(https://projecteuler.net/problem=4)有关,因此:

回文数字两种方式相同。由两个2位数字的乘积制成的最大回文是9009 = 91×99。 找到由两个3位数字的乘积制成的最大回文。

我目前仍然在第1章(SICP),并且尚未涵盖循环,因为我看到大多数解决方案都使用。每次我尝试执行时,我的代码都会耗尽内存(我已经坚持了几个小时 - https://github.com/polila/Project-Euler/commits?author=polila&since=2018-03-19T04:00:00Z&until=2018-03-20T04:00:00Z)大声笑。

我想要做的是通过线性迭代过程使用递归过程(至少这是我的想法) - 所以在我看来它是这样的,其中a和b是n的最大限制位:

(largest-palindrome a   b   max)
(                  999  999   0)
(                  999  998   0)
(                  999  997   0)
(                   .   .     .)
(                   .   .     .)
(                  999  99    x)
(                  998  998   x)
(                  998  997   x)
(                  998  996   x)
(                  .    .     x)
(                  100  100   x)

我意识到我不必一直走到最小范围,但即使是小型测试用例,例如[90,99]范围的2位数回答,它仍然无法执行。但这是我的代码,我哪里错了???????????

#lang racket

(define (exp a b)
    (define (iter product count)
      (if (= count b)
          product
          (iter (* a product) (+ count 1))))
  (if (= b 0)
      1
      (iter a 1)))

(define (palindrome? ab)
  (define (length ab)
    (define (iter n count)
      (if (= n 0)
          count
          (iter (floor (/ n 10)) (+ count 1))))
    (iter ab 0))
    (define (check-symmetry ab left right)
          (if (> left right)
              (if (= (floor (/ (modulo ab (exp 10 left)) (exp 10 (- left 1))))
                     (floor (/ (modulo ab (exp 10 right)) (exp 10 (- right 1)))))
                  (check-symmetry ab (- left 1) (+ right 1))
                  #f)
              #t))
        (check-symmetry ab (length ab) 1))

(define (largest-palindrome a b max)
 (if (> b 100)
     (if (and (palindrome? (* a b)) (< max (* a b)))
         (largest-palindrome a (- b 1) (* a b))
         (largest-palindrome a (- b 1) max))
     (largest-palindrome (- a 1) (- a 1) (* a b)))
  (if (< a 100)
      max
      0))

1 个答案:

答案 0 :(得分:0)

你有一个正确的总体思路,即从999x999开始一直到100x100。您可以通过在b为回文时终止a x b来提高此方法的效率,这样您就不会在a x b-1等中测试回文,因为这些产品会更小值比a x b

这看起来像是:

999 x 999            -- not palindrome
999 x 998            -- not palindrome
    |
995 x 583            -- palindrome (if current palindrome < this, save this value)
994 x 994            -- not palindrome (Notice the jump here instead of testing 995 x 582)
994 x 993            -- not palindrome
    |
994 x 100            -- not palindrome
993 x 993            -- not palindrome
    |
993 x 913            -- palindrome (if current < this, save this value)
992 x 992            -- not palindrome
    |
100 x 100            -- not palindrome (hit base case and return current palindrome)

largest-palindrome的实现中,第一个if语句,即。 (if (> b 100) ...),是死代码。此外,if语句中的递归步骤也没有基本情况,因此每次因无限递归而耗尽内存的原因。

您可以简化大部分代码。例如,考虑以下palindrome?谓词,检查数字是否等于其数字相反:

(define (palindrome? n)
  (define (in-reverse n acc)
    (if (< n 10)
        (+ (* acc 10) n)
        (in-reverse (quotient n 10)
                    (+ (* acc 10)
                       (remainder n 10)))))
  (= n (in-reverse n 0)))

(palindrome? 1001)
=> #t
(palindrome? 1010)
=> #f

然后,您可以使用此谓词实现largest-palindrome

;; largest-palindrome: Finds the largest palindrome that is a
;; multiple of two numbers, each of which has n digits.
(define (largest-palindrome n)
  (define low (expt 10 (sub1 n)))     ;; if n = 3, low  = 100
  (define high (sub1 (expt 10 n)))    ;; if n = 3, high = 999
  (define (largest a b mymax low high)
    (define prod (* a b))
    (cond
      ((< a low) mymax)
      ((or (< b low)
           (< prod mymax))
       (largest (sub1 a) (sub1 high) mymax low (sub1 high)))
      ((and (> prod mymax)
            (palindrome? prod))
       (largest (sub1 a) (sub1 high) prod b (sub1 high)))
      (else
       (largest a (sub1 b) mymax low high))))
  (largest high high 0 low high))

这适用于n

的各种值
(largest-palindrome 3)
=> 906609
(largest-palindrome 5)
=> 9966006699
(largest-palindrome 7)
=> 99956644665999