Python 中的歐拉 #4 (Euler #4 in Python)


問題描述

Python 中的歐拉 #4 (Euler #4 in Python)

A palindromic number reads the same both ways. The largest palindrome made from the product of two 2‑digit numbers is 9009 = 91 × 99. Find the largest palindrome made from the product of two 3‑digit numbers.

http://projecteuler.net/problem=4

Below is my solution to this problem. It works, but I noticed another solution that used

if x*y < max_seen: continue

like this:

def biggest():
    big_x, big_y, max_seen = 0, 0, 0
    for x in xrange(999,99,‑1):
        for y in xrange(x, 99,‑1): 
            if x*y < max_seen: continue
            if is_palindrome(x*y):
                big_x, big_y, max_seen = x,y, x*y

What I don't get is how that line works. The first time through max_seen = 0 and the first x*y is 999*999 which is greater than 0. So that condition isn't met and the next line is run. Makes sense. Eventually, however, max_seen will be larger than x*y so why does it continue here?

It seems this line isn't even needed because if the condition is or isn't met the program will continue anyway. I suspect I'm not understanding how continue works in Python.

This is my approach:

def find_biggest():
    big_x, big_y, new_pal, max_seen = 0, 0, 0, 0
    for x in range(999, 100, ‑1):
        for y in range(x, 100, ‑1):
            if is_palindrome(x*y) == True:
                new_pal = x*y
                if new_pal > max_seen:
                    big_x, big_y, max_seen = x, y, new_pal

From an efficiency standpoint the program should exit as soon as all new x*y are < max_seen, but 999*100 is less than 998*900 (meaning it couldn't stop yet as it still needs to check 998*y997*y, etc.) so how would you code that?


參考解法

方法 1:

The two approaches are almost the same although the first approach avoids checking the palindrom if the product is smaller than the biggest palindrom already encountered, therefore more efficient.

if x*y < max_seen: continue
if is_palindrome(x*y):
   ...

To answer your first question, in the first approach, max_seen will get large only if it belongs to a palindrom, so it will not eventually get large.

方法 2:

I suspect the reason that the code checks for x*y < max_seen first is that it is an easier test than is_palindrome. If you expect many of your potential x and y values to be no good, it makes sense to do the easiest tests first so that you only need to run the complicated tests a few times.

That said, if x*y < max_seen is true, there won't be any successful tests for the current x value. An optimization could be to replace continue (which goes on to the next y value) with break (which ends the inner loop and so goes on to the next x value).

You could even do something similar for the outer loop, and test if x * 999 < max_seen. If so, you'll never find a better result and you can stop looping. Here's how that would look in code:

def biggest():
    big_x, big_y, max_seen = 0, 0, 0
    for x in xrange(999,99,‑1):
        if x*x < max_seen:
            break # breaks out of outer loop, as no later x value can be better
        for y in xrange(x, 99,‑1): 
            if x*y < max_seen:
                break # breaks out of inner loop, no later y value can be better
            if is_palindrome(x*y):
                big_x, big_y, max_seen = x,y, x*y
    return big_x, big_y, max_seen

方法 3:

Here is an efficient general solution (~5x faster than others):  

def pgen(factor):
    ''' Generates stream of palindromes smaller than factor**2 
    starting with largest possible palindrome '''
    pmax = str(factor**2)
    half_palindrome = int(pmax[0:len(pmax)/2]) ‑ 1
    for x in xrange(half_palindrome, 0, ‑1):
        yield int(str(x) + str(x)[::‑1])

def biggest(factor):
    ''' Returns largest palindrome and factors '''
    for palindrome in pgen(factor):
        for f1 in xrange(factor/11*11, factor/10, ‑11):
            f2 = palindrome/f1
            if f2 > factor:
                break
            if f2*f1 == palindrome:
                return palindrome, f1, f2

>>> biggest(99)
(9009, 99, 91)
>>> biggest(999)
(906609, 993, 913)
>>> biggest(9999)
(99000099, 9999, 9901)
>>> biggest(99999)
(9966006699L, 99979, 99681L)
>>> biggest(9999999)
(99956644665999L, 9998017, 9997647L)
>>> biggest(99999999)
(9999000000009999L, 99999999, 99990001L)
>>> biggest(999999999)
(999900665566009999L, 999920317, 999980347L)

(by caadridermuratguBlckknghtdansalmo)

參考文件

  1. Euler #4 in Python (CC BY‑SA 3.0/4.0)

#continue #Python






相關問題

skrip shell: loop bersarang dan lanjutkan (shell script : nested loop and continue)

syntaxError:“繼續”在循環中不正確 (syntaxError: 'continue' not properly in loop)

php continue - 替代方式? (php continue - alternative way?)

Python 中的歐拉 #4 (Euler #4 in Python)

if-continue vs 嵌套 if (if-continue vs nested if)

如何返回上一個 while 循環? (How do I return to the previous while loop?)

php foreach 繼續 (php foreach continue)

在while循環中繼續的奇怪行為 (weird behaviour of continue in while loop)

是否可以使用 'yield' 來生成 'Iterator' 而不是 Scala 中的列表? (Is it possible to use 'yield' to generate 'Iterator' instead of a list in Scala?)

BASH:在 for 循環中使用 continue (BASH: Using a continue in a for loop)

rand() 函數後繼續指令的問題 (Problem with continue instruction after rand() function)

在tictactoe遊戲中重複輸入錯誤 (Error in repeating input in a tictactoe game)







留言討論