Самый большой продукт палиндрома - проект Эйлера

Я пытался решить задачу 4 проекта Euler, а именно:

Палиндромное число одинаково читается в обоих случаях. Самый большой палиндром, составленный из произведения двух двузначных чисел, равен 9009 = 91 × 99. Найдите самый большой палиндром, составленный из произведения двух трехзначных чисел.

Вот мое решение, оно выводит 997799, однако это не правильный ответ, интересно, в чем проблема:

package projecteuler;

public class Pro4 {

    public static void main(String[] args) {

        for(int i=999*999;i>=100*100;i--){
            if(isPalindrome(i)==true){
                System.out.println(i);
                break;
            }
        }
    }

    static boolean isPalindrome(int x){
        int[] bits = new int[7];
        int index=1;
        while(x>0){
            bits[index]=x%10;
            index++;
            x/=10;
        }
        for(int i=1;i<=index/2;i++){
            if(bits[i]!=bits[index-i]){
                return false;
            }
        }
        return true;
    }

}

person Praveen Kumar    schedule 16.07.2014    source источник
comment
Вы проверили это через отладчик? Откровенно говоря, с этим может быть много чего не так - изучение его с помощью пошагового отладчика было бы хорошим первым шагом к выяснению проблемы.   -  person Makoto    schedule 16.07.2014


Ответы (16)


Вот решение, которое не перебирает все 6-значные числа:

public static boolean isPalindrome(int nr) {
    int rev = 0;                    // the reversed number
    int x = nr;                     // store the default value (it will be changed)
    while (x > 0) {
        rev = 10 * rev + x % 10;
        x /= 10;
    }
    return nr == rev;               // returns true if the number is palindrome
}

public static void main(String[] args) {

    int max = -1;

    for ( int i = 999 ; i >= 100 ; i--) {
        for (int j = 999 ; j >= 100 ; j-- ) {
            int p = i * j;
            if ( max < p && isPalindrome(p) ) {
                max = p;
            }
        }
    }
    System.out.println(max > -1? max : "No palindrome found");
}

Изменить:

Улучшенное решение для метода main (по словам Питера Шютце) может быть следующим:

public static void main(String[] args) {

    int max = -1;

    for ( int i = 999 ; i >= 100 ; i--) {
        if ( max >= i*999 ) { 
            break;
        }
        for (int j = 999 ; j >= i ; j-- ) {             
            int p = i * j;
            if ( max < p && isPalindrome(p) ) {
                max = p;
            }
        }
    }       
    System.out.println(max > -1? max : "No palindrome found");
}

Для этого конкретного примера время примерно в 2 раза лучше, но если у вас большие числа, улучшение будет более значительным.

Вывод:

906609
person Elrond_EGLDer    schedule 09.11.2014
comment
+1 за это лучшее решение на данный момент. Еще мне нравится то, что вы сначала сравниваете с максом, прежде чем определить, палиндром ли это. Эта недорогая операция может сэкономить некоторое время. Тем не менее, есть место для оптимизации. 1) вы рассчитываете почти все произведения дважды, так как i*j=j*i вам нужно вычислить произведение только для всех j>=i. 2) для малых i нет j < 1000, которые будут производить продукт больше, чем max. поэтому добавление if ( max / i > 1000) {i=99} эффективно сократит время вычисления максимального палиндрома до 1/10 или меньше текущего времени. - person Peter Schuetze; 11.11.2014
comment
Как мы можем обобщить самое низкое максимальное значение? Поскольку вы инициализируете max до 100001 для трех цифр - person mohit uprim; 09.07.2018
comment
@mohituprim, я отредактировал сообщение, потому что это значение было неправильным. Даже если это палиндром, 100001 не может быть записано как произведение 2-х 3-значных чисел. Вместо этого вы можете использовать 110011 в качестве правильного начального значения. К сожалению, у меня нет правила, которое могло бы работать для всех комбинаций, поэтому использование отрицательного значения /100*100 применимо для всех ситуаций, даже если оно медленнее. - person Elrond_EGLDer; 09.07.2018
comment
@ROMANIA_engineer, могу ли я запустить и протестировать приведенный выше код онлайн? Пожалуйста, предложите веб-сайт. - person pmh; 28.02.2020
comment
@pmh, да, вот 2 хороших примера: ideone.com и repl.it/languages/java10. - person Elrond_EGLDer; 29.02.2020

Вы последовательно уменьшаете i с 999*999 до 100*100. Это не обязательно означает, что первый палиндром, который вы найдете, является произведением двух трехзначных чисел.

Палиндром 997799 имеет 11 и 90709 в качестве простых делителей, которые не являются произведением двух трехзначных чисел.

person Sanjeev Kumar    schedule 16.07.2014
comment
Вопрос был о наибольшем палиндромном произведении двух трехзначных чисел. - person RhythmInk; 14.11.2015

Цикл for выполняется для i от 998001 до 100000. Нигде в вашей программе вы не проверяете, что i может быть произведением двух трехзначных чисел.

person Robby Cornelissen    schedule 16.07.2014
comment
на самом деле его цикл работает от 999 * 999, что составляет 998001 до 100000. ;) - person Peter Schuetze; 01.11.2014
comment
@PeterSchuetze Спасибо. Исправлено. - person Robby Cornelissen; 01.11.2014

Вы повторяете цикл for с числом от 998001 до 10000, поскольку некоторое число может не быть произведением двух трехзначных чисел.
Вы должны умножить два трехзначных числа, а затем сравнить их, является ли это число палиндромом или нет.

Ваш код цикла for должен быть:

  for(int i=999;i>=100;i--)  
  {
        int k = i-1;
        int product = i * k;
        System.out.println(i+" * "+k+"  = "+product);

        if(isPalindrome(product)==true){
            System.out.println("palindrum number "+product);
            System.out.println("Product of : "+i+" * "+k);
            break;
        }
  }  

Это даст вам наибольшее число палиндрома, которое является произведением двух трехзначных чисел.
Вывод:

palindrum number 289982
Product of : 539 * 538  

Это верно, если оба числа различны при умножении.
Если вы хотите включить произведение одного и того же числа, чтобы проверить, является ли оно палиндромом или нет, то в приведенном выше коде могут быть небольшие изменения.
Для этого кода должно быть:

for(int i=999;i>=100;i--){
        int k = i;
        int product = i * k;
        System.out.println(i+" * "+k+"  = "+product);

        if(isPalindrome(product)==true){
            System.out.println("palindrum number "+product);
            System.out.println("Product of : "+i+" * "+k);
            break;
        }
        else{
            k = i - 1;
            product = i * k;
            System.out.println(i+" * "+k+"  = "+product);
            if(isPalindrome(product)==true){
                System.out.println("palindrum number "+product);
                System.out.println("Product of : "+i+" * "+k);
                break;
            }
        }
    }

Что дает вам вывод, например:

palindrum number 698896
Product of : 836 * 836

Я думаю, это то, что вам нужно сделать.

person Yagnesh Agola    schedule 16.07.2014
comment
Ваш ответ хороший, но неправильный. Вы сравниваете только продукт i*(i-1). Самое большое, что я нашел, было 913*993=906609. - person Peter Schuetze; 01.11.2014

Вы также предполагаете, что первый палиндром, который вы найдете, будет самым большим. Первый палиндром, который вы найдете, это 580085, что не является правильным ответом.

Вы также предполагаете, что первый палиндром, который вы найдете, является произведением двух трехзначных чисел. Вы также должны использовать два разных числа вместо умножения 999 на 999 и повторения до 100 * 100.

person Saif Al Falah    schedule 28.09.2015

Ни один из вышеперечисленных не дал правильного ответа. (Я думаю, что логика может быть правильной, но правильный ответ — 906609). Поскольку вы не знаете, является ли число 6-значным или 5-значным, вы хотите проверить, какое из них. Ниже приведен простой код, чтобы сделать то же самое.

Умножение вызывается один раз на часто, я знаю...

i = 999
for u in range (100,1000):
    for y in range (100,1000):
        if len(str(u*y)) == 5 and str(u*y)[0]==str(u*y)[4]and str(u*y)[1]==str(u*y)[3] and u*y>i:
        i=u*y
        print ('the product of ', u, ' and ',y,' is: ',u*y)
    elif len(str(u*y)) == 6 and str(u*y)[0]==str(u*y)[5]and str(u*y)[1]==str(u*y)[4]and str(u*y)[2]==str(u*y)[3]and u*y>i:
        i=u*y
        print ('the product of ', u, ' and ',y,' is: ',u*y)
person SOLID    schedule 21.01.2016

Ну, я вижу здесь много неправильных вещей.

  • Прежде всего, вы используете умножение двух самых высоких трехзначных чисел, а затем уменьшаете его, чтобы найти палиндром. Что вам нужно сделать в соответствии с вопросом, так это использовать переменные, имеющие самые высокие 3-значные номера, а затем уменьшать их, чтобы проверить полученный продукт.
  • Второй для проверки, если нет. является палиндромом, вы использовали массив для его хранения, а затем использовали цикл для его проверки, я считаю это неправильным, так как вы могли просто сохранить полученный результат no. в другую целочисленную переменную, используя простой подход.(reverseNum * 10 + (num % 10))

И я вижу правильный код, уже отправленный пользователем (РУМЫНИЯ)

person Vikas Tawniya    schedule 03.09.2016

/* Найдите наибольший палиндром, составленный из произведения двух n-значных чисел. Поскольку результат может быть очень большим, вы должны вернуть наибольший мод палиндрома 1337. Пример: Ввод: 2 Вывод: 987 Объяснение: 99 x 91 = 9009, 9009 % 1337 = 987 Примечание. Диапазон n равен [1,8] . */

    public class LargestPalindromeProduct {
    public int largestPalindrome(int n) {
        if(n<1 || n>8)
            throw new IllegalArgumentException("n should be in the range [1,8]");

        int start = (int)Math.pow(10, n-1); // n = 1, start 1, end = 10 -1.   n = 2, start = 10, end = 99; 
        if(start == 1) start = 0 ; // n = 3, start = 100, end == 999
        int end = (int)Math.pow(10, n) - 1;

        long product = 0;
        long maxPalindrome = 0;

        for(int i = end ; i >= start ; i--)
        {
            for(int j = i ; j >= start ; j--)
            {
                product = i * j ;
                 // if one of the number is modulo 10, product can never be palindrome, e.g 100 * 200 = 200000, or 240*123 = 29520. this is because the product will always end with zero but it can never begin with zero except one/both of them numbers is zero. 
                if(product % 10 == 0)
                    continue; 
                if(isPalindrome(product) && product > maxPalindrome)
                    maxPalindrome = product;                    
            }
        }
        return (int)(maxPalindrome % 1337);
    }
    public static boolean isPalindrome(long n){
        StringBuffer sb = new StringBuffer().append(Long.toString(n)).reverse();
        if(sb.toString().equals(Long.toString(n)))
            return true;
        return false;
    }
    public static void main(String[] args){
         System.out.println(new LargestPalindromeProduct().largestPalindrome(2));
    }

}
person Tesfay K. Aregay    schedule 10.04.2017

Этот метод значительно быстрее, чем предыдущие методы. Он начинается с оценки 999 * 999. Это реализация метода, предложенного в Puzzled над проблемой палиндромного произведения

Мы хотели бы попробовать более крупные продукты перед более мелкими, поэтому в следующий раз попробуйте 998 * 998, при этом внешний цикл каждый раз уменьшается на единицу. Во внутреннем цикле возьмите внешнее предельное число, чтобы создать (n+y)(n-y) (которое всегда меньше, чем n^2), перебирая y до тех пор, пока один из факторов не станет слишком большим или слишком маленьким.

Из https://pthree.org/2007/09/15/крупнейшее-палиндромное-число-в-питоне/, один из множителей должен быть кратен 11. Проверьте, не кратен ли один из множителей 11 и что произведение больше предыдущего найденное (или исходное) палиндромное число.

Как только эти тесты будут удовлетворены, проверьте, является ли произведение палиндромом.

Как только палиндром найден, мы можем увеличить предел внешнего цикла до квадратного корня из палиндрома, поскольку это минимальное значение, которое может быть ответом.

Этот алгоритм нашел ответ всего в 475 сравнениях. Это намного лучше, чем 810 000, предложенных простыми методами, или даже 405 450.

Может ли кто-нибудь предложить более быстрый метод?

Longest palindromes:
Max factor   Max Palindrome
9999         99000099
99999        9966006699
999999       999000000999
9999999      99956644665999
99999999     9999000000009999
999999999    999900665566009999

public class LargestPalindromicNumberInRange {
    private final long lowerLimit;
    private final long upperLimit;
    private long largestPalindrome;
    private long largestFirstFactor;
    private long largestSecondFactor;
    private long loopCount;
    private long answerCount;

public static void main(String[] args) {
    long lowerLimit = 1000;
    long upperLimit = 9999;
    LargestPalindromicNumberInRange palindromicNumbers = 
            new LargestPalindromicNumberInRange(lowerLimit, upperLimit);
    palindromicNumbers.TopDown();
}

private LargestPalindromicNumberInRange(long lowerLimit, long upperLimit){
    this.lowerLimit = lowerLimit;
    this.upperLimit = upperLimit;
}
private void TopDown() {
    loopCount = 0;
    answerCount = 0;
    largestPalindrome = lowerLimit * lowerLimit;
    long initialLargestPalindrome = largestPalindrome;
    long lowerFactorLimit = lowerLimit;
    for (long limit = upperLimit; limit > lowerFactorLimit; limit--){
        for (long firstFactorValue = limit; firstFactorValue >= limit - 1; firstFactorValue--) {
            long firstFactor = firstFactorValue;
            long secondFactor = limit;
            while(secondFactor <= upperLimit && firstFactor >= lowerLimit){
                if (firstFactor % 11 == 0 || secondFactor % 11 == 0) {
                    long product = firstFactor * secondFactor;
                    if (product < largestPalindrome) { break; }
                    loopCount++;
                    if (IsPalindromic(product)) {
//                    System.out.print("Answer: " + product + "\n");
                        answerCount++;
                        largestPalindrome = product;
                        largestFirstFactor = firstFactor;
                        largestSecondFactor = secondFactor;
                        lowerFactorLimit = (long) Math.sqrt(largestPalindrome);
                        break;
                    }
                }
                firstFactor--;
                secondFactor++;
            }
        }
        System.out.print("Answer: " + largestPalindrome + "\n");
        System.out.print("Factor1: " + largestFirstFactor + "\n");
        System.out.print("Factor2: " + largestSecondFactor + "\n");
        System.out.print("Loop count: " + loopCount + "\n");
        System.out.print("Answer count: " + answerCount + "\n");
    }
private boolean IsPalindromic(Long x) {
    String forwardString = x.toString();

    StringBuilder builder = new StringBuilder();
    builder.append(forwardString);
    builder = builder.reverse();
    String reverseString = builder.toString();

    return forwardString.equals(reverseString);
}

}

person mturner    schedule 15.02.2018

JAVASCRIPT
Эй, я просмотрел некоторые ответы, и они были очень запутанными, вот что я получил: Сначала я вызываю функцию getPalindrome() из кнопки и даю ей только количество цифр. Затем с помощью первого цикла for я устанавливаю max на наибольшее число с предоставленными цифрами, добавляя 9 * 10 ^ 0 (9), 9 * 10 ^ 1 (90) и т. д. Затем у меня есть два вложенных цикла, которые идут от последних двух цифры вниз (напр. 99 и 98). Условие первого цикла в основном не имеет значения, потому что самый большой палиндром всегда будет в последних числах (например, между 90 и 99, 990 и 999 и т. д.). Внутри цикла я проверяю, не делятся ли оба числа на 11, что означает, что у нас не может быть палиндрома, поэтому я просто пропускаю его и уменьшаю второе число. Если одно из них делится на 11, вызывается функция проверки на палиндром. Хотя я не думаю, что это решение лучше/быстрее других, оно проще и понятнее.

const getPalindrome = () => {
let max = 0;
for (let i = 0; i < digit; i++) {
  max += 9 * Math.pow(10, i);
}
let min = (max + 1)/10;
let first = max;
let second = max - 1;

for (let i = first; i > min; i--) {
  for (let j = second; j > min * 9; j--) {
    if(i % 11 !== 0 && j % 11 !== 0) {
      continue;
    } else {
      if(checkForPalindrome(i*j)) {
        return setResult(i*j);
      }
    }
  }
} 


}

  const checkForPalindrome = (num) => {
    let digits = `${num}`;
    for (let i = 0; i < Math.floor(digits.length / 2); i++) {
      if(digits[i] !== digits[digits.length-1-i]) {
        return false;
      } 
    }
    return true;
  }
person Gi-Totv    schedule 10.03.2021
comment
Так что же не так с кодом в вопросе? - person Null; 10.03.2021
comment
Я не понимаю вопроса. Я думал, что другие ответы имеют более сложный код, чем то, что я придумал. Поэтому я хотел поделиться своим решением, даже если оно может быть медленнее, чем другие, по крайней мере, оно короче и проще для понимания. - person Gi-Totv; 12.03.2021

Сделано на C. Это может вам помочь.

#include<stdio.h>
int calculate(int n)
{
    int temp = 0,m = 0;
    m = n;
    while(n != 0)
    {
        temp = temp * 10;
        temp = temp + n % 10;
        n = n / 10;
    }
    if(m == temp)
    {
        printf(" %d \n",temp);
        return temp;
    }
    else
    {
        return 0;
    }
}
int main()
{
    int i,j,temp = 0,count=0,temp1 = 0;
    for(i = 100;i < 1000;i++)
    {
        for(j = 100;j < 1000;j++)
        {
            temp1 = i * j;
            temp = calculate(temp1);

            if(temp > count)
            {
                count = temp;
            }
        }   
    }
    printf(" The Largest Palindrome number is : %d \n",count);
}
person Dhaval Mistry    schedule 03.03.2017

Так как никто не делал в R. Это решение, которое дает ответ на проблему.

Проект Эйлера Вопрос 4

Палиндромное число одинаково читается в обоих случаях. Самый большой палиндром, составленный из произведения двух двузначных чисел, равен 9009 = 91 × 99.

Найдите наибольший палиндром, составленный из произведения двух трехзначных чисел. В R нет встроенной функции для проверки палиндромов, поэтому я создал ее, хотя можно использовать 'rev' :). Также код не оптимизируется по скорости специально, в первую очередь, для повышения читабельности.

       reverse <- function(x){
        Args:
       x : object whose elements are to be reversed, can be of type 
       'character' or 'vector' of length = 1
       Returns:
          x : The object's elements are reversed e.g boy becomes yob and 23 
       becomes 32
       Error Handling:
      if (is.vector(x) == TRUE & length(x) > 1){
        stop("Object whose length > 1 cannot be used with reverse(x) 
        consider vector.reverse(x)")
          }
         Function Execution
         if (is.character(x) == TRUE){
           v <- unlist(strsplit(x, ''))
             N <- length(v)
           rev.v <- v
          for (i in 0:(N - 1)){
         rev.v[i + 1] <- v[N - i]
        }
         rev.v <- paste0(rev.v, collapse = '')
            return(rev.v)
         } else {
            x <- as.character(x)
       v <- unlist(strsplit(x, ''))
           rev.v <- v
            N <- length(v)
 for (i in 0:(N - 1)){
   rev.v[i + 1] <- v[N - i]
 }
rev.v <- paste0(rev.v, collapse = '')
rev.v <- as.numeric(rev.v)
  return(rev.v)
   }
 }

    the function vector.reverse() has been deleted to reduce the length of 
    this code

    is.palindrome <- function(x){
  Args:
     x : vector whose elements will be tested for palindromicity, can be of 
 length >= 1
  Returns:
    TRUE : if an element in x or x is palindromic
    FALSE: if an element in x or x is not palindromic

   Function Execution:
  if (is.vector(x) == TRUE & length(x) > 1){
    x.prime <- vector(length = length(x))
    for (i in 1:length(x)){
      x.prime [i] <- reverse(x [i])
 }
   return(x.prime == x)
 } else {
 ifelse(reverse(x) == x, return(TRUE), return(FALSE))
     }
   }

  palindromes between 10000 and 999*999
 Palin <- (100*100):(999*999)
 Palin <- Palin [is.palindrome(Palin) == 1]
 i.s <- vector('numeric', length = length(Palin))
 j.s <- vector('numeric', length = length(Palin))

   Factoring each of the palindromes
   for (i in 100:999){
     for (j in 100:999){
       if (sum(i * j == Palin) == 1){
         i.s[i-99] <- i
         j.s[i-99] <- j

      }
     }
   }
 product <- i.s * j.s
 which(i.s * j.s == max(product)) -> Ans
 paste(i.s[Ans[1]], "and", j.s[Ans[1]], "give the largest two 3-digit 
  palindrome")



ANSWER
  993 * 913 = 906609

НАСЛАЖДАЙТЕСЬ!

person python9712    schedule 05.05.2017

Еще одно простое решение, написанное на C#.

private static void Main(string[] args)
        {
            var maxi = 0;
            var maxj = 0;
            var maxProd = 0;
            for (var i = 999; i > 100; i--)
            for (var j = 999; j > 100; j--)
            {
                var product = i * j;
                if (IsPalindrome(product))
                    if (product > maxProd)
                    {
                        maxi = i;
                        maxj = j;
                        maxProd = product;
                    }
            }
            Console.WriteLine(
                "The highest Palindrome number made from the product of two 3-digit numbers is {0}*{1}={2}", maxi, maxj,
                maxProd);
            Console.ReadKey();
        }

        public static bool IsPalindrome(int number)
        {
            var numberString = number.ToString();
            var reverseString = string.Empty;
            for (var i = numberString.Length - 1; i >= 0; --i)
                reverseString += numberString[i];
            return numberString == reverseString;
        }
person Santhosh    schedule 31.05.2017

Вот код на с++

#include <iostream>
using namespace std;
int reverse(int a){
int reverse=0;
for(int i=0;i<6;i++){
    reverse = reverse*10+a%10;
    a/=10;
}
return reverse;
}
int main(){
int a=999,max=1,rev;;
int b=999;
for(a=999;a>100;a--){
    for(b=999;b>100;b--){
        int p = a*b;
         rev = reverse(p);
        if (p==rev) {
            if(max<rev){
                max = rev;
            }
        }
    }
}
cout<<"\n"<<max<<"\n";
return 0;
  }
person Community    schedule 01.06.2018

Вот код Python для задачи Project_Euler-4.

Нам нужно найти наибольшее число-палиндром, являющееся произведением двух трехзначных чисел.

import math
def isPal(x):
    x=str(x)
    t=x[::-1]
    if(x==t):
        return True
    else:
        return False
max=0
for i in range(999,99,-1):
    for j in range(999,99,-1):
        if(isPal(i*j)):
            if((i*j)>max):
                max=(i*j)
print(max)

Ответ будет 906609

person Rajesh Sinha    schedule 05.08.2018

person    schedule
comment
Дампы кода не дают хороших ответов. Вы должны объяснить, как и почему это решает их проблему. Я рекомендую прочитать, Как написать хороший ответ? - person John Conde; 17.02.2021