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

前端 未结 17 997
天涯浪人
天涯浪人 2021-02-02 04:27
package testing.project;

public class PalindromeThreeDigits {

    public static void main(String[] args) {
        int value = 0;
        for(int i = 100;i <=999;i+         


        
17条回答
  •  清歌不尽
    2021-02-02 05:10

    We can translate the task into the language of mathematics.

    For a short start, we use characters as digits:

    abc * xyz = n 
    
    abc is  a 3-digit number, and we deconstruct it as 100*a+10*b+c
    xyz is  a 3-digit number, and we deconstruct it as 100*x+10*y+z
    

    Now we have two mathematical expressions, and can define a,b,c,x,y,z as € of {0..9}.
    It is more precise to define a and x as of element from {1..9}, not {0..9}, because 097 isn't really a 3-digit number, is it?

    Ok.

    If we want to produce a big number, we should try to reach a 9......-Number, and since it shall be palindromic, it has to be of the pattern 9....9. If the last digit is a 9, then from

    (100*a + 10*b + c) * (100*x + 10*y + z) 
    

    follows that z*c has to lead to a number, ending in digit 9 - all other calculations don't infect the last digit.

    So c and z have to be from (1,3,7,9) because (1*9=9, 9*1=9, 3*3=9, 7*7=49).

    Now some code (Scala):

    val n = (0 to 9)
    val m = n.tail // 1 to 9
    val niners = Seq (1, 3, 7, 9)
    val highs = for (a <- m;
      b <- n;
      c <- niners; 
      x <- m;
      y <- n;
      z <- niners) yield ((100*a + 10*b + c) * (100*x + 10*y + z))
    

    Then I would sort them by size, and starting with the biggest one, test them for being palindromic. So I would omit to test small numbers for being palindromic, because that might not be so cheap.

    For aesthetic reasons, I wouldn't take a (toString.reverse == toString) approach, but a recursive divide and modulo solution, but on todays machines, it doesn't make much difference, does it?

    // Make a list of digits from a number: 
    def digitize (z: Int, nums : List[Int] = Nil) : List[Int] =
      if (z == 0) nums else digitize (z/10, z%10 :: nums)
    
    /* for 342243, test 3...==...3 and then 4224. 
       Fails early for 123329 */
    def palindromic (nums : List[Int]) : Boolean = nums match {
      case Nil           => true 
      case x :: Nil      => true 
      case x :: y :: Nil => x == y 
      case x :: xs       => x == xs.last && palindromic (xs.init) }
    
    def palindrom (z: Int) = palindromic (digitize (z))
    

    For serious performance considerations, I would test it against a toString/reverse/equals approach. Maybe it is worse. It shall fail early, but division and modulo aren't known to be the fastest operations, and I use them to make a List from the Int. It would work for BigInt or Long with few redeclarations, and works nice with Java; could be implemented in Java but look different there.

    Okay, putting the things together:

    highs.filter (_ > 900000) .sortWith (_ > _) find (palindrom) 
    res45: Option[Int] = Some(906609)
    

    There where 835 numbers left > 900000, and it returns pretty fast, but I guess even more brute forcing isn't much slower.

    Maybe there is a much more clever way to construct the highest palindrom, instead of searching for it.

    One problem is: I didn't knew before, that there is a solution > 900000.


    A very different approach would be, to produce big palindromes, and deconstruct their factors.

提交回复
热议问题