patternMinor
Finding palindromic numbers most efficiently
Viewed 0 times
efficientlynumbersfindingmostpalindromic
Problem
After reading why is my project euler #4 program not working?, I was contemplating the most efficient way to approach this (finding the target palindrome as early as possible).
Is this snippet about as efficient as it gets? I am only considering the merits of the logic, not the choice of language. It would be easier (but not as efficient) to brute-force it with two nested loops.
Also, is this logic common enough for it to have a name?
Is this snippet about as efficient as it gets? I am only considering the merits of the logic, not the choice of language. It would be easier (but not as efficient) to brute-force it with two nested loops.
Also, is this logic common enough for it to have a name?
#!/usr/bin/perl
use strict;
$^W = 1;
$\ = "\n";
my ($n) = @ARGV;
$n = 3 if (! defined $n || $n 8);
my ($lo,$hi,$lm);
$lo = substr('10000000000',0,$n);
$hi = substr('99999999999',0,$n);
$lm = substr('100000000000000000000',0,$n*2);
my ($a,$b,$x) = ($hi,$hi);
for (;;) {
$x = $a*$b;
if ($x eq reverse $x) {
print "$x is $a * $b" if ($x > $lm);
last if ($n > 3); # show them all for small numbers
}
next if (!(--$a $hi)); # no short-cut operator here
++$a; --$b;
print " edge $a $b" if ($n < 3); # show edge for small numbers
$a += $b; $b = int --$a/2; $a -= $b;
last if ($a*$b < $lm);
}Solution
Here, you first check if
It would be more efficient to do the other way around, checking
With \$n = 3\$, this makes a big difference: it saves reversing
I also tried rewriting the
somewhat inspired by the the duck's comment:
instead of comparing an entire string with its reverse,
it should be more efficient to compare its first half with the reverse of its second half:
Although this function does only half of the comparisons as in
at least as interpreted code, this cannot compete with the speed of the compiled
$x is palindrome, but then you will only print it if $x > $lm:if ($x eq reverse $x) {
print "$x is $a * $b" if ($x > $lm);
last if ($n > 3); # show them all for small numbers
}It would be more efficient to do the other way around, checking
$x > $lm first:if ($x > $lm) {
if ($x eq reverse $x) {
print "$x is $a * $b";
last if ($n > 3); # show them all for small numbers
}
}With \$n = 3\$, this makes a big difference: it saves reversing
$x 23602 times.I also tried rewriting the
reverse operation,somewhat inspired by the the duck's comment:
instead of comparing an entire string with its reverse,
it should be more efficient to compare its first half with the reverse of its second half:
sub is_palindrome {
my ($word) = (@_);
my $l = length($word);
foreach my $i (0 .. $l / 2) {
if (substr($word, $i, 1) ne substr($word, $l - $i - 1, 1)) {
return;
}
}
return 1;
}Although this function does only half of the comparisons as in
$x eq reverse $x,at least as interpreted code, this cannot compete with the speed of the compiled
reverse function. Using this function the script runs much slower, unfortunately.Code Snippets
if ($x eq reverse $x) {
print "$x is $a * $b" if ($x > $lm);
last if ($n > 3); # show them all for small numbers
}if ($x > $lm) {
if ($x eq reverse $x) {
print "$x is $a * $b";
last if ($n > 3); # show them all for small numbers
}
}sub is_palindrome {
my ($word) = (@_);
my $l = length($word);
foreach my $i (0 .. $l / 2) {
if (substr($word, $i, 1) ne substr($word, $l - $i - 1, 1)) {
return;
}
}
return 1;
}Context
StackExchange Code Review Q#63304, answer score: 2
Revisions (0)
No revisions yet.