john
john

Reputation: 11669

Optimizing the largest palindrome from product of two three digit numbers?

I am working on an interview question which I was asked in which I was supposed to write a program to find the largest palindrome from product of two three digit numbers.

Here is the question

I came up with this brute force approach which starts from bottom.

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;
    }
}

They asked me what are the optimizations I can do in this program? I mentioned that we can try pruning the search space and optimize checking step for each item in the search space but then I am confuse how would I make this work in my above solution?

What are the optimizations we can do in this program? Right now it is executing 810000 steps to find the largest palindrome.

What is the least number of steps we can execute to find the largest palindrome in two three digit numbers?

Upvotes: 5

Views: 506

Answers (6)

RARE Kpop Manifesto
RARE Kpop Manifesto

Reputation: 2817

this obviously isn't java but it's just a proof of concept on how to use regex to batch generate palindromes (of any sort) without having to manually do divisions, modulos, or string reversals :

  • To make even length palindromes, simply double the width of the central column starting point.

(just realized a minor bug of not including the combinations with 2nd and 4th column zeros in the 5-digit variant.)


  # gawk profile, created Fri Feb  2 04:52:00 2024

  # BEGIN rule(s)

   BEGIN {
 4      for (_ = _ < _; _++ < 4; ) {
 4          print _, "\f\f\r\t", _______(_)
    }
    }


# Functions, listed alphabetically

 4  function _______(__, _,___,____) {

 4      ___ = "123456789" (____ = "")

 4      if ((__ = int(__)) <= (_^=_<_)+_) {

 2          gsub(/./, _<__ ? ",&&" : __<_ ? ____ : ",&", ___)

 2          return substr(___, _+_)
        }

 2      ____ = __-_-_
 2        __ = (!_)___
 2         _ = "."
 2      gsub(_, "&\\&&", ___)

 3      while (____--)
 3          gsub(_,___, __) < (_ = ("..")_)

 2      gsub(_, ",&", __)
        gsub((_=(_=(".")_)_)_ (_)_ (_)_ "[,]?", "&\n", __)

 2      return substr(__, ++_+_)
    }

 1  1 
    1,2,3,4,5,6,7,8,9

 2  2 
    11,22,33,44,55,66,77,88,99

 3  3 
    101,202,303,404,505,606,707,808,909,111,212,313,
 4  414,515,616,717,818,919,121,222,323,424,525,626,
 5  727,828,929,131,232,333,434,535,636,737,838,939,
 6  141,242,343,444,545,646,747,848,949,151,252,353,
 7  454,555,656,757,858,959,161,262,363,464,565,666,
 8  767,868,969,171,272,373,474,575,676,777,878,979,
 9  181,282,383,484,585,686,787,888,989,191,292,393,
10  494,595,696,797,898,999

11  5            
    11011,21012,31013,41014,51015,61016,71017,81018,91019,12021,22022,32023,
12  42024,52025,62026,72027,82028,92029,13031,23032,33033,43034,53035,63036,
13  73037,83038,93039,14041,24042,34043,44044,54045,64046,74047,84048,94049,
14  15051,25052,35053,45054,55055,65056,75057,85058,95059,16061,26062,36063,
15  46064,56065,66066,76067,86068,96069,17071,27072,37073,47074,57075,67076,
16  77077,87078,97079,18081,28082,38083,48084,58085,68086,78087,88088,98089,
17  19091,29092,39093,49094,59095,69096,79097,89098,99099,11111,21112,31113,
18  41114,51115,61116,71117,81118,91119,12121,22122,32123,42124,52125,62126,
19  72127,82128,92129,13131,23132,33133,43134,53135,63136,73137,83138,93139,
20  14141,24142,34143,44144,54145,64146,74147,84148,94149,15151,25152,35153,
21  45154,55155,65156,75157,85158,95159,16161,26162,36163,46164,56165,66166,
22  76167,86168,96169,17171,27172,37173,47174,57175,67176,77177,87178,97179,
23  18181,28182,38183,48184,58185,68186,78187,88188,98189,19191,29192,39193,
24  49194,59195,69196,79197,89198,99199,11211,21212,31213,41214,51215,61216,
25  71217,81218,91219,12221,22222,32223,42224,52225,62226,72227,82228,92229,
26  13231,23232,33233,43234,53235,63236,73237,83238,93239,14241,24242,34243,
27  44244,54245,64246,74247,84248,94249,15251,25252,35253,45254,55255,65256,
28  75257,85258,95259,16261,26262,36263,46264,56265,66266,76267,86268,96269,
29  17271,27272,37273,47274,57275,67276,77277,87278,97279,18281,28282,38283,
30  48284,58285,68286,78287,88288,98289,19291,29292,39293,49294,59295,69296,
31  79297,89298,99299,11311,21312,31313,41314,51315,61316,71317,81318,91319,
32  12321,22322,32323,42324,52325,62326,72327,82328,92329,13331,23332,33333,
33  43334,53335,63336,73337,83338,93339,14341,24342,34343,44344,54345,64346,
34  74347,84348,94349,15351,25352,35353,45354,55355,65356,75357,85358,95359,
35  16361,26362,36363,46364,56365,66366,76367,86368,96369,17371,27372,37373,
36  47374,57375,67376,77377,87378,97379,18381,28382,38383,48384,58385,68386,
37  78387,88388,98389,19391,29392,39393,49394,59395,69396,79397,89398,99399,
38  11411,21412,31413,41414,51415,61416,71417,81418,91419,12421,22422,32423,
39  42424,52425,62426,72427,82428,92429,13431,23432,33433,43434,53435,63436,
40  73437,83438,93439,14441,24442,34443,44444,54445,64446,74447,84448,94449,
41  15451,25452,35453,45454,55455,65456,75457,85458,95459,16461,26462,36463,
42  46464,56465,66466,76467,86468,96469,17471,27472,37473,47474,57475,67476,
43  77477,87478,97479,18481,28482,38483,48484,58485,68486,78487,88488,98489,
44  19491,29492,39493,49494,59495,69496,79497,89498,99499,11511,21512,31513,
45  41514,51515,61516,71517,81518,91519,12521,22522,32523,42524,52525,62526,
46  72527,82528,92529,13531,23532,33533,43534,53535,63536,73537,83538,93539,
47  14541,24542,34543,44544,54545,64546,74547,84548,94549,15551,25552,35553,
48  45554,55555,65556,75557,85558,95559,16561,26562,36563,46564,56565,66566,
49  76567,86568,96569,17571,27572,37573,47574,57575,67576,77577,87578,97579,
50  18581,28582,38583,48584,58585,68586,78587,88588,98589,19591,29592,39593,
51  49594,59595,69596,79597,89598,99599,11611,21612,31613,41614,51615,61616,
52  71617,81618,91619,12621,22622,32623,42624,52625,62626,72627,82628,92629,
53  13631,23632,33633,43634,53635,63636,73637,83638,93639,14641,24642,34643,
54  44644,54645,64646,74647,84648,94649,15651,25652,35653,45654,55655,65656,
55  75657,85658,95659,16661,26662,36663,46664,56665,66666,76667,86668,96669,
56  17671,27672,37673,47674,57675,67676,77677,87678,97679,18681,28682,38683,
57  48684,58685,68686,78687,88688,98689,19691,29692,39693,49694,59695,69696,
58  79697,89698,99699,11711,21712,31713,41714,51715,61716,71717,81718,91719,
59  12721,22722,32723,42724,52725,62726,72727,82728,92729,13731,23732,33733,
60  43734,53735,63736,73737,83738,93739,14741,24742,34743,44744,54745,64746,
61  74747,84748,94749,15751,25752,35753,45754,55755,65756,75757,85758,95759,
62  16761,26762,36763,46764,56765,66766,76767,86768,96769,17771,27772,37773,
63  47774,57775,67776,77777,87778,97779,18781,28782,38783,48784,58785,68786,
64  78787,88788,98789,19791,29792,39793,49794,59795,69796,79797,89798,99799,
65  11811,21812,31813,41814,51815,61816,71817,81818,91819,12821,22822,32823,
66  42824,52825,62826,72827,82828,92829,13831,23832,33833,43834,53835,63836,
67  73837,83838,93839,14841,24842,34843,44844,54845,64846,74847,84848,94849,
68  15851,25852,35853,45854,55855,65856,75857,85858,95859,16861,26862,36863,
69  46864,56865,66866,76867,86868,96869,17871,27872,37873,47874,57875,67876,
70  77877,87878,97879,18881,28882,38883,48884,58885,68886,78887,88888,98889,
71  19891,29892,39893,49894,59895,69896,79897,89898,99899,11911,21912,31913,
72  41914,51915,61916,71917,81918,91919,12921,22922,32923,42924,52925,62926,
73  72927,82928,92929,13931,23932,33933,43934,53935,63936,73937,83938,93939,
74  14941,24942,34943,44944,54945,64946,74947,84948,94949,15951,25952,35953,
75  45954,55955,65956,75957,85958,95959,16961,26962,36963,46964,56965,66966,
76  76967,86968,96969,17971,27972,37973,47974,57975,67976,77977,87978,97979,
77  18981,28982,38983,48984,58985,68986,78987,88988,98989,19991,29992,39993,
78  49994,59995,69996,79997,89998,99999

Upvotes: 0

ugur
ugur

Reputation: 3654

First optimize isPalindrome by seperating 6 digits as 3 digits. i.e. N = ABCDEF => a = ABC = N/1000, b = DEF = N%1000; Then reverse b and return a==reversed_b;

Secondly while producing palindromes loop through till max_palindrome_so_far/999 which is the minimum value that you would use. max_palindrome_so_far is initially equals 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);
        }
    }
}

Upvotes: 0

גלעד ברקן
גלעד ברקן

Reputation: 23955

The least number of steps I could get to is 375. Consider multiplying the three-digit number, a1a2a3, by the three-digit number, b1b2b3:

JavaScript code:

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);

Output:

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

Upvotes: 0

Aki Suihkonen
Aki Suihkonen

Reputation: 20027

One useful mechanism to prune the search tree is to notice that the highest digit of the product a * b doesn't change often. E.g.

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)

Thus, for all the values in between (a = 111, a < b < 181), one already knows the MSB, which must equal to the LSB or (a % 10) * (b % 10) % 10 == MSB.

 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

Most of the time there's either none, or just one candidate in set 'b' to be checked for any pair MSB, a % 10.

Upvotes: 1

Paul Boddington
Paul Boddington

Reputation: 37645

The program looks very good to me. I would make the i loop count from 999 down to 100, and I would only check j values that would actually give a larger product than the current maximum.

This program is able to finish surprisingly soon, at i == 952 to be precise. 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 where the larger factor is less than the square-root of 906609, which is 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);
}

Upvotes: 4

user4668606
user4668606

Reputation:

One pretty simple way of optimizing this would be to simply start with the highest 3-digit numbers instead of the smallest. Since the solution will most likely be closer to the pair (999 , 999) than to (100 , 100).

Upvotes: 1

Related Questions