欧拉问题编号#4

时间:2009-02-16 23:21:46

标签: python palindrome

使用Python,我试图解决problem #4问题的Project Euler。有人可以告诉我我做错了什么吗?问题是找到由两个3位数字的产品制成的最大回文。这是我到目前为止所做的。

import math

def main(): 
    for z in range(100, 1000):
        for y in range(100, 1000):
            for x in range(1, 1000000):
                x = str(x)
                if x == x[::-1] and x == z*y:
                    print x 

if __name__ == '__main__':
    main()

12 个答案:

答案 0 :(得分:10)

一些效率问题:

  1. 从顶部开始(因为我们可以在跳过大量计算时使用它)
  2. 不要重复计算
  3. def is_palindrome(n):
        s = str(n)
        return s == s[::-1]
    
    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):  # so we don't double count   
                if x*y < max_seen: continue  # since we're decreasing, 
                                    # nothing else in the row can be bigger
                if is_palindrome(x*y):
                    big_x, big_y, max_seen = x,y, x*y
    
        return big_x,big_y,max_seen
    
    biggest()
    # (993, 913, 906609)
    

答案 1 :(得分:9)

尝试从z和y的乘积计算x,而不是检查从1到100的每个数字。想一想:如果你被要求计算500 * 240,哪个更有效 - 乘以它们,或从1开始计算直到找到正确的答案?

答案 2 :(得分:4)

以下是一些要记住的一般优化。发布的代码处理所有这些,但这些是可以帮助解决未来问题的一般规则:

1)如果你已经检查过z = 995,y = 990,你不需要检查z = 990,y = 995.Greg Lind正确处理这个

2)你计算z * y的乘积然后你在一个巨大的范围内运行x并将该值与y * z进行比较。例如,您刚刚计算了900 * 950,然后将x从1000运行到1M,并查看x = 900 * 950。你看到了这个问题吗?

3)此外,以下代码会发生什么? (这就是为什么你的代码什么也没有返回,但你不应该这样做)

x = str(100)
y = 100
print x == y

4)如果你弄清楚(3),你将在那里打印很多信息。您需要找出存储最大值的方法,并且最后只返回该值。

5)这是计算欧拉问题的好方法:

if __name__ == "__main__":
    import time
    tStart = time.time()
    print "Answer = " + main()
    print "Run time = " + str(time.time() - tStart)

答案 3 :(得分:1)

将字符串与

中的整数进行比较
x == z*y

还存在逻辑错误

以相反的顺序range(999, 99, -1)开始。那会更有效率。完全删除第三个循环和第二个比较。

答案 4 :(得分:1)

而不是枚举所有3位数字的产品(约900 ^ 2次迭代), 列举所有6位和5位数的palyndromes(这需要大约1000次迭代); 然后对每个palyndrome决定它是否可以由产品代表 两个3位数字(如果不能,它应该有一个4位数的素数因子, 所以这很容易测试。)

另外,你问的问题是#4,而不是#3。

答案 5 :(得分:0)

问题陈述:

What is the largest prime factor of the number 600851475143?

我使用C#解决了这个问题,但算法本身与语言无关。

  1. 创建一种方法,用于确定数字是否为素数。这可能是暴力(而不是使用更有效的筛分算法),看起来像这样:

  2. private static long IsPrime(long input)
            {
                if ((input % 2) == 0)
                {
                    return 2;
                }
                else if ((input == 1))
                {
                    return 1;
                }
                else
                {
                    long threshold = (Convert.ToInt64(Math.Sqrt(input)));
                    long tryDivide = 3;
                    while (tryDivide < threshold)
                    {
                        if ((input % tryDivide) == 0)
                        {
                            Console.WriteLine("Found a factor: " + tryDivide);
                            return tryDivide;
                        }
                        tryDivide += 2;
                    }
                    Console.WriteLine("Found a factor: " + input);
                    return -1;
                }
            }
    
    1. 一旦我有了确定素数的函数,我就可以使用这个函数来找到最高素因子

    2. private static long HighestPrimeFactor(long input)
      {
          bool searching = true;
          long highestFactor = 0;
          while (searching)
          {
              long factor = IsPrime(input);
              if (factor != -1)
              {
                  theFactors.Add(factor);
                  input = input / factor; 
              }
              if (factor == -1)
              {
                  theFactors.Add(input);
                  highestFactor = theFactors.Max();
                  searching = false;
              }
          }
          return highestFactor;
      }
      

      我希望这会有所帮助,而不会放弃太多。

答案 6 :(得分:0)

这里的其他建议很棒。此代码也有效。我从999开始,因为我们知道可能的最大组合是999 * 999。不是python,而是一些快速完成的伪代码。

public static int problem4()
    {       
    int biggestSoFar=0;
        for(int i = 999; i>99;i--){
            for(int j=999; j>99;j--){
                if(isPaladrome(i*j))
                   if(i*j>biggestSoFar)
                        biggestSoFar=i*j;
            }
        }
        return biggestSoFar;    
    }

答案 7 :(得分:0)

这是您可能考虑的解决方案。它可能效率更高,但只需要一点时间就可以运行。

largest = 0
for a in range(100, 1000):
    for b in range(100, 1000):
        c = a * b
        if str(c) == ''.join(reversed(str(c))):
            largest = max(largest, c)
print(largest)

答案 8 :(得分:0)

这是一个有效的通用解决方案(比我见过的其他人快〜5倍):

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)

答案 9 :(得分:-1)

如果你的程序运行缓慢,并且你有这样的嵌套循环:

for z in range(100, 1000):
    for y in range(100, 1000):
        for x in range(1, 1000000):

然后你应该问自己的问题是:“最内层循环的主体会执行多少次?” (最内层循环的主体是以:x = str(x)

开头的代码

在这种情况下,很容易弄明白。外循环将执行900次。 对于每次迭代,中间循环也将执行900次 - 这使得900×900或810,000次。然后,对于810,000次迭代中的每次迭代,内部循环本身将执行999,999次。我想我需要很长时间来计算:

>>> 900*900*999999
809999190000L

换句话说,你的回文检查几乎达到了810亿次次。如果你想使每个问题的项目欧拉建议限制为1分钟,你可能想要优化一点:-)(参见David的评论)

答案 10 :(得分:-1)

这就是我在Java中所做的:

public class Euler0004
{
    //assumes positive int
    static boolean palindrome(int p)
    {
        //if there's only one char, then it's
        //  automagically a palindrome
        if(p < 10)
            return true;

        char[] c = String.valueOf(p).toCharArray();

        //loop over the char array to check that
        //  the chars are an in a palindromic manner
        for(int i = 0; i < c.length / 2; i++)
            if(c[i] != c[c.length-1 - i])
                return false;

        return true;
    }


    public static void main(String args[]) throws Exception
    {
        int num;
        int max = 0;

        //testing all multiples of two 3 digit numbers.
        // we want the biggest palindrome, so we
        // iterate backwards
        for(int i = 999; i > 99; i--)
        {
            // start at j == i, so that we
            //  don't calc 999 * 998 as well as
            //  998 * 999...
            for(int j = i; j > 99; j--)
            {
                num = i*j;

                //if the number we calculate is smaller
                //  than the current max, then it can't
                //  be a solution, so we start again
                if(num < max)
                    break;

                //if the number is a palindrome, and it's
                //  bigger than our previous max, it
                //  could be the answer
                if(palindrome(num) && num > max)
                    max = num;
            }
        }

        //once we've gone over all of the numbers
        //  the number remaining is our answer
        System.out.println(max);

    }
}

答案 11 :(得分:-1)

这是我的解决方案:

polindroms = [(x, y, x * y) for x in range(100, 999) for y in range(100, 999) if str(x * y) == str(x * y)[::-1]]
print max(polindroms, key = lambda item : item[2])