关于python:Project Euler#4算法的可能优化

Possible optimizations for Project Euler #4 algorithm

Find the largest palindrome made from the product of two 3-digit numbers.

尽管算法对于手头的问题足够快,但我想知道是否遗漏了任何明显的优化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from __future__ import division
from math import sqrt

def createPalindrome(m):
    m = str(m) + str(m)[::-1]
    return int(m)

def problem4():
    for x in xrange(999,99,-1):
        a = createPalindrome(x)
        for i in xrange(999,int(sqrt(a)),-1):
            j = a/i
            if (j < 1000) and (j % 1 == 0):
                c = int(i * j)
                return c


在我的代码中,最大的减速似乎是将一个整数转换为一个字符串,将其反向添加,然后将结果转换回一个整数。

我查找了更多关于回文的信息,偶然发现了这个公式,它允许我将3位数字"n"转换为6位回文数字"p"(可适用于其他数字,但我不担心)。

P=1100*N?990*?n/10??99*?n/100?

我的原始代码在0.75毫秒内运行,而新的代码几乎花费相同的时间(更不用说,公式必须根据"n"的位数进行调整),所以我想没有多少优化需要执行。


当我刚开始学习Python时,我写了这篇文章,但这里是:

1
2
3
4
5
6
7
8
9
10
11
12
for i in range (999, 800, -1):

for j in range (999,800, -1):

    number = i*j
    str_number = str(number)

rev_str_number = str_number[::-1]

if str_number == rev_str_number:

    print("%s a palendrome") % number

我没有检查你所有的号码,但我还是得到了正确的答案。在这个练习中,我真正学到的是":"以及它的工作原理。你可以在这里看看。

祝欧拉好运!


看看这里有什么想法

在C++中,我这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int euler004()
    {
    // 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.
    const int N=3;
    const int N2=N<<1;
    int min,max,a,b,c,i,j,s[N2],aa=0,bb=0,cc=0;
    for (min=1,a=1;a<N;a++) min*=10; max=(min*10)-1;
    i=-1;
    for (a=max;a>=min;a--)
     for (b=a;b>=min;b--)
        {
        c=a*b; if (c<cc) continue;
        for (j=c,i=0;i<N2;i++) { s[i]=j%10; j/=10; }
        for (i=0,j=N2-1;i<j;i++,j--)
         if (s[i]!=s[j]) { i=-1; break; }
        if (i>=0) { aa=a; bb=b; cc=c; }
        }
    return cc; // cc is the output
    }
  • 不需要sqrt…
  • createPalindrome的子调用可以降低由于堆/堆栈垃圾造成的速度。
  • 串操作m = str(m) + str(m)[::-1]
  • 如果在固定大小数组上进行字符串到int的转换,则转换速度会更快。
  • Mine实现大约运行1.7毫秒,但大部分时间是应用程序输出和格式化(w7 x64上的amd 3.2Ghz 32位应用程序)。
  • 小精灵

    [edit1]实现公式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    int euler004()
        {
        int i,c,cc,c0,a,b;
        for (cc=0,i=999,c0=1100*i;i>=100;i--,c0-=1100)
            {
            c=c0-(990*int(i/10))-(99*int(i/100));
            for(a=999;a>=300;a--)
             if (c%a==0)
                {
                b=c/a;
                if ((b>=100)&&(b<1000)) { cc=c; i=0; break; }
                }
            }
        return cc;
        }

    • 这需要~0.4 ms
    • 小精灵

      [edit2]进一步优化

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      //---------------------------------------------------------------------------
      int euler004()
          {
          // 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.
          int i0,i1,i2,c0,c1,c,cc=0,a,b,da;
          for (c0=  900009,i0=9;i0>=1;i0--,c0-=100001)    // first digit must be non zero so <1,9>
          for (c1=c0+90090,i1=9;i1>=0;i1--,c1-= 10010)    // all the rest <0,9>
          for (c =c1+ 9900,i2=9;i2>=0;i2--,c -=  1100)    // c is palindrome from 999999 to 100001
           for(a=999;a>=948;a-- )
            if (c%a==0)
              {
              // biggest palindrome is starting with 9
              // so smallest valid result is 900009
              // it is odd and sqrt(900009)=948 so test in range <948,999>
              b=c/a;
              if ((b>=100)&&(b<1000)) { cc=c; i0=0; i1=0; i2=0; break; }
              }
          return cc;
          }
      //---------------------------------------------------------------------------
      • 这对我来说太快了,无法正确测量时间(原始时间约为0.037 ms)
      • 从回文生成中删除了除法和乘法
      • 在等待总线时,经过一些数值分析和思考,改变了范围
      • 第一个循环可以消除(结果从9开始)
      • 小精灵