### Comment on

 Need Help??

The XOR dance, with a rotating mirror copy. This runs in O(n). Err, it actually runs in O(n2) of course. The inner loop just happens to be shrouded: Perl's string XOR is not O(1).

```sub aristotle {
my \$str = shift;
my \$rts = reverse \$str;

my \$palindrome = '';
for my \$rotate_count ( 0 .. length( \$str ) - 1 ) {
my \$mask = \$str ^ \$rts;

while( \$mask =~ /\0{3,}/g ) {
my \$len = \$+[0] - \$-[0];
next if \$len <= length \$palindrome;
my \$offs = \$-[0];
--\$offs if \$offs > \$rotate_count; # compensate for marker
\$palindrome = substr \$str, \$offs, \$len;
}

substr \$rts, 0, 0, chop \$rts;
}

return \$palindrome;
}

If you don't understand what's going on, run this for a visual demonstration:

```#!/usr/bin/perl
use strict;
use warnings;

sub hd { join ' ', map sprintf("%02X", ord \$_), split //, \$_[0] }

my \$rts = reverse \$str;

for my \$rotate_count ( 0 .. length( \$str ) - 1 ) {
my \$mask = \$str ^ \$rts;

# turn all non-nulls to 0xFF for demonstration purposes

while( \$mask =~ /\0{3,}/g ) {
my \$len = \$+[0] - \$-[0];
my \$offs = \$-[0];
--\$offs if \$offs > \$rotate_count; # compensate for marker
print substr( \$str, \$offs, \$len ), "\n";
}

print "\$rotate_count: ", hd( \$str ), " ^ ", hd( \$rts ), " = ", hd(
substr \$rts, 0, 0, chop \$rts;
}

Update: changed 0 .. POSIX::ceil( length( \$str ) / 2 ) to 0 .. length( \$str ) - 1. It was a vestige from an earlier trail of thought that was no longer valid.

Update: since I was asked how this works, I'm adding an explanation here.

It is pretty simple: a XOR b = 0 when a = b. If you XOR two strings with each other, you will get a NULL at all locations with identical characters. Now obviously, if you XOR a string with a mirror copy of itself and get all NULLs, then it's a palindrome, because all characters in the rotated copy were identical with all characters of the original.

That's the gist of it. The particular problem given for this thread is complicated by the fact that we have to look for embedded palindromes, and rotating the string unfortunately displaces the rotated copy of an embedded palindrome. To find all embedded palindromes, the mirror copy must be XORed against the original string at each offset. The code does this by rotating the copy n times for a string of length n.

There is one nasty trap left. If the string consists of two adjacent palindromes, such as abbabbafef. Mirroring that yields fefabbabba. If you rotate this three times to the left, the mirror copy becomes abbabbafef and XORing them yields a string of all NULLs, which would indicate that the palindrome is abbabbafef. Oops. The problem is that we forgot to keep track of where inside the mirror copy its original start and end used to be. Palindromes obviously cannot run across that location. That is what the substr \$mask, \$rotate_count, 0, "\1"; is about: a non-NULL is added to break a string of NULLs running across that location. Of course, now we have to account for that extra character in offsets in the mask.

And that's it. The bulk of the work happens in a single XOR and a pattern match, and other auxiliary tasks are done using very few builtins. That's where it gets its speed. The bulk of the code is merely simple math.

Makeshifts last the longest.

In reply to Re: Finding longest palindrome from a string by Aristotle
in thread Finding longest palindrome from a string by BUU

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

• Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
• Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
• Read Where should I post X? if you're not absolutely sure you're posting in the right place.
• Posts may use any of the Perl Monks Approved HTML tags:
a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
• You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
 For: Use: & & < < > > [ [ ] ]
• Link using PerlMonks shortcuts! What shortcuts can I use for linking?

Create A New User
Chatterbox?
 [Lady_Aleena]: marioroy, it is used in 24 other modules I wrote. [Lady_Aleena]: GUH! I wrote a script better than I thought! 8) [marioroy]: Wow. It's cool seeing Github coments "Update Monster.pm, Create Wild_hairs, Create alternate- PurpleOnGreen..., Then a location, Create Aleenia. Amazing, really. Thank you for sharing. Discipulus when naming is clear and you know how to arrange the data, then coding it is a mere writing work

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (9)
As of 2017-05-29 09:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
My favorite model of computation is ...

Results (192 votes). Check out past polls.