求两个三位数乘积的最大回文问题

Posted

技术标签:

【中文标题】求两个三位数乘积的最大回文问题【英文标题】:Finding the largest palindrome of the product of two three digit numbers problem 【发布时间】:2010-07-14 22:07:43 【问题描述】:

所以在 Project Euler 中,Problem 4 声明如下:

回文数的读法相同 双向。最大的回文 来自两个 2 位数字的乘积 数字是 9009 = 91 99。

找到最大的回文数 两个 3 位数字的乘积。

我尝试了以下方法:

    #include <stdio.h>
    #include <stdlib.h>

    int check(int result)
    
        char b[7];
        sprintf(b, "%d", result);
        if (b[0] == b[5] && b[1] == b[4] && b[2] == b[3])
        
            return 1;
        
        else 
        
            return 0;
        
    

    int main () 
        int i;
        int g;
        int final;
        for (i = 999; i > 99; i--)
        
            for (g = 999; g > 99; g--)
            
                if (check(g*i) == 1)
                
                    final = g*i;
                    goto here;
                
            
        
        here:
        printf("%d", final);

但是,这不起作用。我得到的不是正确答案,而是 580085,我猜这至少是一个回文,但仍然不是正确答案。

让我从int main开始解释我的程序:

    int iint g 是我的乘数。它们就是那两个三位数。 int final 是存储最大回文数的数字。 我开始了两个 for 循环,以获取每个数字的可能性。 当到达第一个回文时,我使用 goto 退出循环(可能不应该,但它不会对这样的小程序产生太大影响)。 第一个回文应该是最大的回文,因为我从顶部倒数。

现在让我解释一下我的支票:

    首先,因为这是两个三位数相乘以确定一个 char 保持该值所需的大小,所以我用计算器乘以 999 * 999,结果是 6,然后我需要加一个因为我从我之前发布的一个问题中发现sprintf 在末尾添加了一个\0 字符。 好的,既然我有一个字符,我复制了resultint main 中的i*g)并将其放入char b[7]。 然后我检查了b,通过硬编码我需要检查的每个插槽来查看它是否与它自己相同。 然后我相应地返回,1 为真,2 为假。

这对我来说似乎完全合乎逻辑,但是由于某些奇怪的原因它不起作用。有什么提示吗?

【问题讨论】:

你的“g”倒计时太快了——你可能会发现一个基于 999 * 101 的回文,但真正的答案更像是 997 * 867,它更大。 一个提示:乘法是可交换的,因此您可以使用for (g = i; g &gt; 99; g--) 来避免同时测试999*100100*999 顺便说一句,这是 goto 的合法用途 解决这个问题的另一种方法是从 999*999 迭代到 100*100,然后对每个回文测试看它是否是两个 3 位数字的乘积。 【参考方案1】:

这个假设是错误的:

第一个回文应该是最大的一个,因为我从顶部倒数。

你会在998*101 = 100798 之前检查999*100 = 99900,所以显然你不能指望它。

【讨论】:

【参考方案2】:

问题是你找到的第一个回文肯定不是更大的。

只是一个例子:

i = 900, g = 850 -> 765000
i = 880, g = 960 -> 844800

第一个较小,但由于您首先在 i 上进行迭代,然后在 g 上将首先发现它。

好吧,它们不是回文,但概念是一样的..

【讨论】:

【参考方案3】:

我认为您正在从头到尾解决这个问题。从最高到最低生成回文然后通过分解它们来检查会更有效。第一个有两个三位数的因素就是答案。

例如

  bool found = false;
  for (int i = 998; i >= 100; i--)
  
    char j[7];
    sprintf(j,"%d",i);
    j[3]= j[2];
    j[4]= j[1];
    j[5]= j[0];
    int x =atoi(j);
    int limit = sqrt((float) x);
    for (int z = 999; z >= limit; z--)
    
      if (x%z==0)
        printf("%d",x);
        found = true;
        break;
      
    
    if (found) break;
  

【讨论】:

【参考方案4】:

第一个回文应该是最大的,因为我是从上往下倒数

问题是您可能找到了一个大的i 和一个小的g 的回文。 jk 的乘积可能存在更大的回文,其中:

i > j and
g < k

(我希望这是有道理的)。

【讨论】:

【参考方案5】:

Java 实现:

public class Palindrome 

    public static void main(String[] args)
            int i, j;
            int m = 1;
            int k =11;
            boolean flag = false;

            while (true)
            ;
                if (flag) j = m + 1;
                else j = m;

                for (i = k; i > 0; i--)
                

                    j++;



                    int number, temp, remainder, sum = 0;
                    number = temp = (1000 - i) * (1000 - j);

                    while (number > 0)
                    
                        remainder = number % 10;
                        number /= 10;
                        sum = sum * 10 + remainder;
                    

                    if (sum == temp)
                    
                        System.out.println("Max value:"+temp);

                        return;
                    


                

                if (flag)
                    m++;
             k=k+11;
                flag = !flag;
            

     


【讨论】:

【参考方案6】:

关于性能的一句话。您有可能复制许多产品,因为您使用的是非常简单的嵌套循环方法。例如,你从 999*999 开始,然后是 999*998,等等。当内循环结束时,你将减少外循环,然后从 998*999 重新开始,这与 999*998 相同。

真的,您要做的是使用与当前外循环值相同的值启动内循环。这将消除您的重复操作。像这样的...

for (i = 999; i > 99; i--)

  for (g = i; g > 99; g--)
  
...

但是,正如 Emilio 指出的那样,您认为您找到的第一个回文将是答案的假设是不正确的。显然,您需要首先计算最大的数字。所以你应该按这个顺序尝试它们; 999*999、999*998、998*998、999*997、998*997等……

尚未测试,但我认为您想要这样的东西(伪代码):

x = 999;
n = 0;

while (++n <= x)

  j = x;
  k = j - n;

  while (j >= k)
  
    y = j-- * k;
    if (check(y))
      stop looking
  

【讨论】:

【参考方案7】:

我发现这个article 可能会对你有所帮助。它改进了蛮力方法。

【讨论】:

【参考方案8】:

以上提供的所有答案都非常好,但我仍然无法限制自己编写代码。 @thyrgle 发布的代码绝对完美。他需要做的只是稍微修正一下,检查哪个产品是最大的。 代码可以为

int i,j,max=0,temp;
for(i=999;i>=100;i--)
    for(j=i;j>=100;j--)
        temp=i*j;
        if(isPalin(temp) && temp>max)
            max=temp;
        
    

cout<<max<<"\n";

【讨论】:

尽量不要拼错用户名(如 thyrgle)。尝试添加一些东西,比如不要摸索已知太小的产品:maxPalin = 100001 ... for (int lowerBound = maxPalin/i, j = i ; lowerBound &lt;= j ; j--)【参考方案9】:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int a[6];

void convertToString(int xy)
    int i,t=100000;
    for(i=0;i<6;i++)
        a[i]=xy/t;
        xy = xy % t;
        t=t/10;
    


int check()
    int i;
    for(i=0;i<3;i++)
        if(a[i]!=a[6-i])
            return 0;
        
    
    return 1;


void main()
    int x,y,xy,status=0;
    int i=0,j=0,p=0;
    for(x=999;x>99;x--)
        for(y=x;y>99;y--)
            xy=x*y;
            convertToString(xy);
            status = check();
            if(status==1)
                if(xy>p)
                    p=xy;
                    i=x;
                    j=y;
                
            
        
    

    printf("\nTwo numbers are %d & %d and their product is %d",i,j,p);


【讨论】:

【参考方案10】:
x,y=999,999

k=0

pal=[]

while (y>99):
    while (x>=100):
        m=x*y
        n=x*y
        while (n!=0):
            k=k*10+(n%10)
            n=int(n/10)
        if(m==k):
            if k not in pal:
                pal.append(k)
        x=x-1
        k=0
    else:
        y,x=y-1,999


pal.sort()
print(pal)

它给出了 906609 作为最大的回文数

【讨论】:

以上是关于求两个三位数乘积的最大回文问题的主要内容,如果未能解决你的问题,请参考以下文章

几个数字求乘积最大或者最小,思路是啥

几个数字求乘积最大或者最小,思路是啥

Problem 004

Leetcode 479.最大回文数乘积

python中具有3位数字的最高回文

479. 最大回文数乘积