计算回文数遇无限循环,求基于SICP第1章的Racket解法(欧拉计划4题)
用SICP风格的递归解决Project Euler第4题(避免无限循环)
嘿,太懂你现在的处境了——刚啃SICP第一章,满脑子递归,碰Project Euler的题却看到一堆循环解法,还踩了无限循环的坑!我当初学SICP的时候也干过这事,给你分享个纯递归的思路,完全符合第一章的知识范围,还能解决无限循环的问题。
首先,先明确核心问题:我们要找两个三位数乘积里最大的回文数,关键是用递归替代循环,同时给每一步递归设置明确的终止条件——这正是你之前无限循环的根源:没有收敛的边界。
第一步:写一个判断回文数的辅助函数
用Racket的字符串处理很方便,把数字转成字符串,再和反转后的字符串对比就行:
(define (palindrome? n) (let ((s (number->string n))) (equal? s (list->string (reverse (string->list s))))))
(注:Racket里reverse是处理列表的,所以要把字符串转成列表反转后再转回字符串)
第二步:递归遍历所有三位数对,记录最大回文数
我们从最大的三位数999开始往下遍历,对于每个数i,再从i开始往下遍历j(避免重复计算i*j和j*i),一旦i*j比当前找到的最大回文数小,就直接停止这个i的遍历——因为再往下j更小,乘积只会更小,没必要继续。
这里分两个递归函数:
max-palindrome:负责遍历每个i从999到100check-pair:负责遍历每个j从i到100,检查乘积是否为回文
(define (max-palindrome start end current-max) (cond ((< start end) current-max) ; 终止条件:start小于最小三位数,返回当前最大值 (else ; 检查当前start和所有<=它的三位数的乘积,更新最大值 (let ((new-max (check-pair start start current-max))) (max-palindrome (- start 1) end new-max))))) (define (check-pair i j current-max) (let ((product (* i j))) (cond ((< product current-max) current-max) ; 终止条件:乘积比当前最大值小,不用继续找j了 ((palindrome? product) (max product current-max)) ; 是回文数,更新最大值 (else (check-pair i (- j 1) current-max))))) ; 不是回文数,j减1继续检查
第三步:调用函数得到结果
直接调用(max-palindrome 999 100 0),就能得到两个三位数乘积的最大回文数:906609(验证一下:993 × 913 = 906609)
为什么不会无限循环?
每个递归都有明确的终止条件:
max-palindrome里,start从999每次减1,直到小于100就停止check-pair里,要么j减到小于100,要么乘积比当前最大值小就停止,不会一直递归下去
这个思路完全贴合SICP第一章的递归思想,没有用任何循环,还能高效地找到结果。
内容的提问来源于stack exchange,提问作者Patrick Olila
相关产品推荐
相关产品推荐

