Can anyone tell me what\'s wrong with the code. Find the largest palindrome
made from the product of two 3-digit numbers.
function largestPalind
Swift 3:
// my approach is to make 6-digit palindrome first and then
// check if I can divide it by 3-digit number
// (you can see some visual listing at the end of the code)
// execution time on my laptop is around: 2.75409698486328 sec
import Foundation
func maxPalindrom() -> Int {
var result = 999999
var i = 9
var j = 9
var k = 9
while true {
while true {
while true {
print("in K loop: \(result) k = \(k)")
if isDivisible(number: result) {
return result
}
if k <= 0 {
k = 9
result += 9900
break
}
result -= 1100
k -= 1
}
print("in J loop: \(result)")
if isDivisible(number: result) {
return result
}
if j < 0 {
j = 9
result += 90090
break
}
result -= 10010
j -= 1
}
print("in I loop: \(result)")
if isDivisible(number: result) {
return result
}
if i < 0 {
break
}
result -= 100001
i -= 1
}
if result == 100001 {
return -1
}
return -1
}
func isDivisible(number: Int) -> Bool {
var i = 999
while true {
if number % i == 0 && number / i < 999 {
return true
}
if i < 500 {
return false
}
i -= 1
}
}
let start = NSDate()
print(maxPalindrom()) // 906609
let end = NSDate()
print("executio time: \(end.timeIntervalSince(start as Date)) sec") // ~ execution time: 2.75409698486328 sec
//in K loop: 999999 k = 9
//in K loop: 998899 k = 8
//in K loop: 997799 k = 7
//in K loop: 996699 k = 6
//in K loop: 995599 k = 5
//in K loop: 994499 k = 4
//in K loop: 993399 k = 3
//in K loop: 992299 k = 2
//in K loop: 991199 k = 1
//in K loop: 990099 k = 0
//in J loop: 999999
//in K loop: 989989 k = 9
//in K loop: 988889 k = 8
//in K loop: 987789 k = 7
//in K loop: 986689 k = 6
//in K loop: 985589 k = 5
//in K loop: 984489 k = 4
//in K loop: 983389 k = 3
.....
The above solution will work perfectly fine but we will have issue ONLY when we try to find-out what are those 2 numbers (i = 913 and j = 993)
I will just modify the solution proposed by Azder
int max = 0;
int no1 = 0;
int no2 = 0;
// not using i >= 100 since 100*100 is not palindrome! :)
for (var i = 999; i > 100; i--) {
// because i * j === j * i, no need of both i and j
// to count down from 999
for (var j = i; j > 100; j--) {
var mul = j * i;
if (isPalin(mul)) {
if ((i+j) > max) {
max = i+j;
no1 = i; no2 = j;
}
}
}
}
//Now we can get the 2 numbers (no1=993 and no2=913)
return (no1*no2);
I believe this should be optimal
#include <functional>
#include <algorithm>
#include <iostream>
using namespace std;
template <typename T>
bool IsPalindrome(const T num) {
T reverse = 0;
T n = num;
while (n > 0) {
reverse = (reverse * 10) + n % 10;
n /= 10;
}
return reverse == num;
}
template <typename T = long long int>
T LongestPalindromeFromProductOfNDigitNums(int n) {
T result = 0, val = 0, max_n_digit_num = std::pow(10, n)-1,
least_n_digit_num = std::pow(10, n-1);
int n_checks = 0;
for (T i = max_n_digit_num; i >= least_n_digit_num; --i) {
if ((i*i) < result) {//found the highest palindrome
break;
}
for (T j = i; j >= least_n_digit_num; --j) {
val = i*j;
++n_checks;
if (val < result) // any product i*j for the value of 'j' after this will be less than result
break;
if (IsPalindrome(val)) {
if (val > result)
result = val;
break; // whenever a palindrome is found break since we only need highest one
}
}
}
std::cout << " Total num of checks = " << n_checks << std::endl;
return result;
}
int main() {
int n = 3;
std::cout << " LongestPalindromeFromProductOfNDigitNums for n = "
<< n << " is " << LongestPalindromeFromProductOfNDigitNums(n) << std::endl;
n = 4;
std::cout << " LongestPalindromeFromProductOfNDigitNums for n = "
<< n << " is " << LongestPalindromeFromProductOfNDigitNums(n) << std::endl;
return 0;
}
http://ideone.com/WoNSJP
As explained in @VisioN's comment:
995*583 = 580085
is a palindrome.
993*913 = 906609
is also a (larger) palindrome.
Your code checks 995*583
before 993*913
and exits at the first palindrome found, so it doesn't return the largest palindrome.
Solution: get the largest palindromes starting from 999*999 = 998001
downwards and check if they can be written as xyz*abc
.
Or simply use the accepted solution from the question you linked :). Your solution, but instead of returning when you find the first palindrome, check if it is larger than the largest one already found, in which case you need to replace it. You can stop as soon as the largest palindrome is larger than i*999
.
I think if you apply maths to the problem you can decrease the guesswork really significantly.
I will write the three digit numbers as 1000 - a
and 1000 - b
which means the palindrome is 1 000 000 - 1000(a+b) + ab
.
First, let's find solutions where ab < 1000
. Then the three leftmost digits are 1000 - (a+b)
and the three rightmost digits are ab
.
Then I will say this is a palindrome with digits x,y,z
:
100x+10y+z=ab
100z+10y+x=1000-a-b
thus
99x-99z = ab+a+b-1000
x-z = 1/99(ab+a+b-10)-10
So then (ab+a+b-10) is divisible by 99 and we also know that x and z being digits the left side is between -9 and 0 (the whole shebang is symmetrical so we can presume x <= z) so then 1/99(ab+a+b-10)
is between 1 and 9. We can rewrite ab+a+b-10
as ab+a+b+1-11=99p
so (a+1)(b+1)=99p+11=11*(9p+1)
where p runs between 1 and 9. That's really easy:
for ($p = 1; $p <= 9; $p++) {
$n = 9 * $p + 1;
// This could be vastly optimized further.
for ($j = 1; $j <= $n; $j++) {
if ($n % $j === 0) {
$a = 1001 - $n / $j;
$b = 1001 - 11 * $j;
$test = $a * $b;
if (strrev($test) === (string) $test) {
print "$a $b " . $a * $b . "\n";
}
}
}
}
Now this prints only one solution which is the correct one.
Now we know 906609 is a solution so then is there a solution where ab > 1000 and 1000(a+b) - ab < 93391 ? There is not :)
Readable option:
function maxPalindrome(num) {
let maxPalindrome = 1;
for (let i = num; i > 0; i--) {
for (let j = num; j > 0; j--) {
const product = i * j;
if (
product.toString() === product.toString().split("").reverse().join("")
&& product > maxPalindrome
) {
maxPalindrome = product;
}
}
}
return maxPalindrome;
}
console.log(maxPalindrome(999));