Reputation: 11669
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
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 :
(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
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
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
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
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