【问题标题】:Python nested for loops output unpredictable?Python嵌套for循环输出不可预测?
【发布时间】:2018-01-22 18:09:42
【问题描述】:

我为project Euler question #4 编写了以下代码:

回文数的两种读法相同。由两个 2 位数字的乘积构成的最大回文数是 9009 = 91 × 99。

找出由两个 3 位数字相乘的最大回文数。

def foo():
for x in xrange (999,100,-1):
    for y in xrange (999,100,-1):
        product= (x*y)
        if str(product)== str(product)[::-1]:
            print product
foo()

此代码生成所有回文的连续输出,因为我省略了中断。但是输出如下:

580085
514415
906609
119911
282282
141141
853358
650056
601106
..
..

我不明白为什么最大的数字没有首先打印出来。 C 中的类似代码在最顶部给出了最大的数字。我缺少关于 Python for 循环的东西吗?

【问题讨论】:

  • 您应该更仔细地查看xy 的价值观在生产这些产品...
  • 尝试用print x,y,product 代替print product,看看你注意到了什么。
  • 由于 C 中没有 xrange,我很好奇“C 中的类似代码”是什么样的。
  • 如果您希望对回文进行排序,请在 for 循环期间将它们存储在列表中,然后排序并在末尾打印。
  • 我希望你注意到你的输出包含每个回文两次。作为初学者,您确定要使用Python 2 而不是 Python 3?

标签: python python-2.7


【解决方案1】:

仔细研究产生产品的价值会回答您的问题。第一个数字580085x = 995y = 583 生成。同样,第三个产品906609x = 993y = 913 生产。循环按应有的方式反向迭代。

碰巧最大的回文不一定由最大的被乘数生成。

如果你想找到最大的回文,把这个函数转换成一个生成器,然后在上面调用max。此外,正如 cmets 中所指出的,您将每对数字迭代两次,一次作为 x-y 对,另一次作为 y-x 对。稍微修改你的第二个循环,这样你就不必执行那些冗余计算。 y 应该下降到 x,而不是 100

def foo(l, u):
    for x in xrange(u, l, -1):
        for y in xrange(u, x - 1, -1):
            v = x * y
            if str(v) == str(v)[::-1]:
                yield v

这样称呼它:

>>> max(foo(100, 999))
906609

对于 python-3.x,将 xrange 更改为 range


当您谈论 C 代码给您预期的输出时,我也很好奇您的意思。于是我写了一点代码来测试:

#include <stdio.h>
#include <string.h>

char buf[42];

# https://stackoverflow.com/a/31397607/4909087
int is_palindrome(char const* s)
{
   int len = strlen(s);
   if ( len == 0 ) // An empty string a palindrome
   {
      return 1;
   }

   int i = 0;
   int j = len-1;
   for ( ; i < j; ++i, --j )
   {
      if ( s[i] != s[j] )
      {
         // the string is not a palindrome.
         return 0;
      }
   }

   // If we don't return from inside the for loop,
   // the string is a palindrome.
   return 1;
}


int main(){    
    int x, y; 
    for (x = 999; x >= 100; x--)
        for (y = 999; y >= 100; y--) 
        {
            sprintf(buf, "%d", x * y);
            if(is_palindrome(buf)){
                printf("%d\n", x * y);
            }    
        }

    return 0;
}

编译运行返回:

$ gcc test.c
$ ./a.out

580085
514415
906609
119911
282282
141141
853358
650056
601106
592295
543345
485584
...

这与您使用 Python 程序获得的数字完全相同。请注意,这仍然是低效的,正确的做法是将内部循环的定义更改为for (y = 999; y &gt;= x; y--)

【讨论】:

    【解决方案2】:

    其中的诀窍是循环从内循环迭代到外循环。首先,内部循环的外部循环的值为 999,然后内部循环的外部循环的值为 998。

    结果产品没有按降序排序,因为(例如 995 * 583

    【讨论】:

      【解决方案3】:

      虽然已经有更好的答案,但只是发布输出的生成方式。 我刚刚修改了 Py3 的代码。正如其他人解释的那样,这种行为是正常的。由于外部循环的 x 值将减少 1,因此仅当内部循环的 y 达到 100 时,您看到的输出不是降序排列的。

      for x in range(999,100,-1):
          for y in range(999,100,-1):
              product= (x*y)
              if str(product)== str(product)[::-1]:
                  print('x is ' + str(x) + '; y is ' + str(y))
                  print(product)
      

      输出:

      x is 995; y is 583
      580085
      x is 995; y is 517
      514415
      x is 993; y is 913
      906609
      x is 991; y is 121
      119911
      x is 987; y is 286
      282282
      x is 987; y is 143
      141141
      x is 982; y is 869
      853358
      x is 979; y is 664
      650056
      x is 979; y is 614
      601106
      x is 979; y is 605
      592295
      x is 979; y is 555
      543345
      x is 979; y is 496
      485584
      x is 979; y is 446
      436634
      x is 979; y is 387
      378873
      x is 979; y is 337
      329923
      x is 978; y is 418
      408804
      

      【讨论】:

        【解决方案4】:

        这是您的代码的一个版本,它将根据您的查找从最高到最低打印值。

        它更优化一点,因为它避免了多余的乘法,并过滤掉了无论如何都可能发生的重复。 (例如 111*9 == 333*3 == 999)。

        我在 Python 3 中执行此操作。您可能需要为 Python 2 手动导入 Set 模块。

        def foo():
            result = set()
            for x in range (999,1,-1):
                for y in range (999,x,-1):
                    product= (x*y)
                    if str(product)== str(product)[::-1]:
                        result.add(x*y)
            result = list(result)
            result = sorted(result,reverse=True)
            for i in result:
                 print(i)
        foo()
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-06-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-07-12
          • 2013-10-17
          • 1970-01-01
          相关资源
          最近更新 更多