【问题标题】:Optimizing the largest palindrome from product of two three digit numbers?从两个三位数的乘积中优化最大回文?
【发布时间】:2015-04-29 01:34:37
【问题描述】:

我正在处理一个面试问题,有人问我,我应该编写一个程序来从两个三位数的乘积中找到最大的回文。

这里是question

我想出了这种从底部开始的蛮力方法。

public class LargestPalindromeQuestion {

    public static void main(String[] args) {
        int value = 0;
        for (int i = 100; i <= 999; i++) {
            for (int j = i; j <= 999; j++) {
                int value1 = i * j;
                if (isPalindrome(value1) && value < value1) {
                    value = value1;
                }
            }
        }
        System.out.println(value);
    }

    private static boolean isPalindrome(final int product) {
        int p = product;
        int reverse = 0;
        while (p != 0) {
            reverse *= 10;
            reverse += p % 10;
            p /= 10;
        }
        return reverse == product;
    }
}

他们问我可以在这个程序中做哪些优化?我提到我们可以尝试修剪搜索空间并优化搜索空间中每个项目的检查步骤,但是我很困惑如何在上述解决方案中实现这一点?

我们可以在这个程序中做哪些优化?现在它正在执行810000 步骤来寻找最大的回文。

我们可以执行的最少步数是多少,才能在两个三位数中找到最大的回文数?

【问题讨论】:

  • 这可能会有所帮助(我正在解决同样的问题,所以我还没有阅读)mathblog.dk/project-euler-problem-4
  • 假设前导零不允许作为回文的一部分,任何以零结尾的数字都不能是回文。因此,您可以跳过 i % 10 == 0 或 j % 10 == 0 的所有 i 和 j 值,因为乘以以 0 结尾的值会得到以 0 结尾的结果。

标签: java algorithm optimization palindrome


【解决方案1】:

这个程序在我看来非常好。我会将i 循环计数从999 减少到100,并且我只会检查j 的值,这些值实际上会产生比当前最大值更大的产品。

这个程序能够很快完成,准确地说是i == 952。这样做的数学原因是,一旦找到解906609 (993 * 913),就不再可能找到更大的回文数小于906609 的平方根,即952.160....

public static void main(String[] args) {
    int value = 0;
    for (int i = 999; i >= 100; i--) {
        int r = value / i;
        if (r >= i) {
            System.out.println("We broke at i = " + i);
            break;
        }
        for (int j = i; j > r; j--) {
            int value1 = i * j;
            if (isPalindrome(value1)) {
                value = value1;
                break;
            }
        }
    }
    System.out.println(value);
}

【讨论】:

  • 你能解释一下这行"The mathematical reason for this is that once the solution 906609 (993 * 913) is found, it will no longer be possible to find a larger palindrome"吗?我无法理解为什么在那之后我们将无法找到更大的回文?
  • @david 在此代码中,i 表示两个 3 位数字中较大的一个。如果i &lt;= 952,那么j也将是&lt;= 952(因为它小于或等于i),所以i * j将小于906609,这意味着没有意义继续。跨度>
【解决方案2】:

一种非常简单的优化方法是简单地从最高的 3 位数字开始,而不是从最小的数字开始。因为解决方案很可能更接近 (999 , 999) 对而不是 (100 , 100)。

【讨论】:

  • 这很好。如果在找到第一个回文时使用break; 语句,这将减少步数。您将无法获得良好的估计,但它将减少检查
  • 如果你把 i 从 999 倒数到 100,你可以在找到回文后打破,并且 i * 999 小于你找到的最高回文,因为在那之后就不可能找到更高的回文了一。如果 j 在 i * j 小于目前找到的最高值时倒计时,您也可以中断内部循环(但不是外部循环)
  • 这个说法没有证据,也有可能最大回文出现在
  • @Vikram Bhat 我试过了。它比 (100 , 100) 更接近 (999 , 999)。除此之外,还有很多对 (n , n) 会产生回文。没错,这只是猜测,但通过查看数字,您可能会发现这是合理的。
  • @VikramBhat 如果你向上数,那么你永远无法打破,因为你永远不知道你是否会找到更高的。所以这种方式即使是也更快
【解决方案3】:

修剪搜索树的一个有用机制是注意产品a * b 的最高数字不会经常变化。例如

a = 111;   b = 112   a*b = 12432
       ;   b = 113   a*b = 12543
       ;   b = 114   a*b = 12654
       ;   ...
       ;   b = 180   a*b = 19980
       ;   b = 181   a*b = 20091 = (19980 + a)

因此,对于介于 (a = 111, a

 e.g.
 LSB = 1    --> a % 10 == 1, b % 10 == 1
            OR  a % 10 == 3, b % 10 == 7
            OR  a % 10 == 7, b % 10 == 3
            OR  a % 10 == 9, b % 10 == 9

大多数情况下,要么没有,要么只有一个候选者在集合“b”中被检查任何一对 MSB,a % 10。

【讨论】:

    【解决方案4】:

    我能达到的最少步数是 375。考虑将三位数字 a1a2a3 乘以三位数字 b1b2b3

    JavaScript 代码:

    var modHash = new Array(10);
    var iterations = 0;
    
    for (var i=1; i<10; i++){
      modHash[i] = {0: [0]}
      for (var j=1; j<10; j++){
        iterations ++;
        var r = i * j % 10;
        if (modHash[i][r])
          modHash[i][r].push(j);
        else 
          modHash[i][r] = [j];
      }
    }
    
    var highest = 0;
    
    function multiples(x,y,carry,mod){
    
      for (var i in modHash[x]){
        var m = (10 + mod - i - carry) % 10;
    
        if (modHash[y][m]){
          for (var j in modHash[x][i]){
            for (var k in modHash[y][m]){
              iterations ++;
              var palindrome = num(9,modHash[y][m][k],x,9,modHash[x][i][k],y);
    
              if (x == 3 && mod == 0){
                console.log(x + " * " + modHash[x][i][j] + " + " 
                            + y + " * " + modHash[y][m][k] + ": " + palindrome);
              }
    
              var str = String(palindrome);
    
              if (str == str.split("").reverse().join("") && palindrome > highest){
                highest = palindrome;
              }
            }
          }
        }
      }
    }
    
    function num(a1,a2,a3,b1,b2,b3){
      return (100*a1 + 10*a2 + a3)
           * (100*b1 + 10*b2 + b3);
    }
    
    var a3b3s = [[7,7,4],[9,1,0],[3,3,0]];
    
    for (var i in a3b3s){
      for (var mod=0; mod<10; mod++){
        var x = a3b3s[i][0],
            y = a3b3s[i][1],
            carry = a3b3s[i][2];
        multiples(x,y,carry,mod);
      }
    }
    
    console.log(highest);
    console.log("iterations: " + iterations);
    

    输出:

    3 * 0 + 3 * 0: 815409 
    3 * 7 + 3 * 3: 907809 
    3 * 4 + 3 * 6: 908109 
    3 * 1 + 3 * 9: 906609 
    3 * 8 + 3 * 2: 907309 
    3 * 5 + 3 * 5: 908209 
    3 * 2 + 3 * 8: 907309 
    3 * 9 + 3 * 1: 906609 
    3 * 6 + 3 * 4: 908109 
    3 * 3 + 3 * 7: 907809
    906609
    iterations: 375
    

    【讨论】:

      【解决方案5】:

      首先优化 isPalindrome,将 6 位数字分隔为 3 位数字。即N = ABCDEF => a = ABC = N/1000,b = DEF = N%1000;然后反转 b 并返回 a==reversed_b;

      其次,在生成回文时循环直到 max_palindrome_so_far/999,这是您将使用的最小值。 max_palindrome_so_far 最初等于 N。

      public class Solution {
      
          public static boolean isPalindrome(int n){
              int a = n/1000;
              int b = n%1000;
              int d, r = 0, i = 3;
              while(i-- > 0){
                  d = b%10;
                  r = r*10 + d;
                  b = b/10;
              }
              if (a == r)
                  return true;
              return false;
          }
      
          public static void main(String[] args) {
              Scanner in = new Scanner(System.in);
              int t = in.nextInt();
              for(int a0 = 0; a0 < t; a0++){
                  int n = in.nextInt();
                  int r=0, m=n;
                  int i,j;
                  for(i = 999;i>=100;i--){
                      for(j = 999;j>=m/999;j--){
                          if (i*j < n && i*j > 100000 && isPalindrome(i*j)){
                              r = Math.max(i*j, r);
                              m = r;
                          }
                      }
                  }
      
                 // System.out.println(i + " * " + j + " = " + i*j);
      
                  System.out.println(r);
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2014-01-31
        • 2023-03-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-04
        • 1970-01-01
        相关资源
        最近更新 更多