Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding palindromes in a linked list

This is an interview question(again).

Given a singly connected linked list, find the largest palindrome in the list. (You may assume the length of the palindrome is even)

The first approach I made was using a stack - we traverse over the list from the start and keep pushing in the letters. Whenever we find the letter on the top of the stack is same as the next letter on the linked list, start popping(and incrementing the linked list pointer) and set a count on the number of letters that matches. After we find a mismatch, push back all the letters that you popped from the stack, and continue your pushing and popping operations. The worst case complexity of this method would be O(n2) e.g. when the linked list is just a string of the same letters.

To improve on the space and time complexity(by some constant factors), I proposed copying the linked list to an array and finding the largest sized palindrome in the array which again takes O(n2) time complexity and O(n) space complexity.

Any better approach to help me with? :(

like image 727
letsc Avatar asked Aug 13 '11 07:08

letsc


3 Answers

One could come up with a O(n²)-algorithm with O(1) space complexity as follows:

Consider f→o→b→a→r→r→a→b:

Walk through the list reversing the links while visiting. Start with x=f and y=f.next:

  • set x.next = null
  • f o→b→a→r→r→a→b
    ^ ^
    |  \
    x   y
    and check for how many links both lists (x and y) are equal.
  • Now continue. (tmp=y.next, y.next=x, x=y, y=tmp) E.g. in the second step, it will yield f←o b→a→r→r→a→b, with x=o and y=b, now you check again if it's a palindrome and continue:
  • f←o←b a→r→r→a→b
  • f←o←b←a r→r→a→b
  • f←o←b←a←r r→a→b yay :)
  • etc.

If you need to restore the list again, reverse it again in O(n)

like image 71
rumpel Avatar answered Nov 11 '22 00:11

rumpel


This is a well analyzed problem with O(N) time complexity.

  • You can reverse the original string(let's say str and str_reversed)

Then the problem is transformed to: find the longest common substring in str and str_reversed.

  • An O(N) approach is building a suffix tree(O(N)) with constant time lowest common ancestor retrieval.
like image 21
Mu Qiao Avatar answered Nov 11 '22 00:11

Mu Qiao


If you copy the lists to an array, the following could be useful: Since we consider only even-length-palindromes, I assume this case. But the technique can be easily extended to work wich odd-length-palindromes.

We store not the actual length of the palindrome, but half the length, so we know how many characters to the left/right we can go.

Consider the word: aabbabbabab. We are looking for the longest palindrome.

a a b b a b b a b a b (spaces for readability)
°^°                   start at this position and look to the left/right as long as possible,
 1                    we find a palindrome of length 2 (but we store "1")
                      we now have a mismatch so we move the pointer one step further
a a b b a b b a b a b
   ^                  we see that there's no palindrome at this position, 
 1 0                  so we store "0", and move the pointer
a a b b a b b a b a b
  ° °^° °             we have a palindrome of length 4, 
 1 0 2                so we store "2"
                      naively, we would move the pointer one step to the right,
                      but we know that the two letters before pointer were *no*
                      palindrome. This means, the two letters after pointer are
                      *no* palindrome as well. Thus, we can skip this position
a a b b a b b a b a b
         ^            we skipped a position, since we know that there is no palindrome
 1 0 2 0 0            we find no palindrome at this position, so we set "0" and move on
a a b b a b b a b a b
      ° ° °^° ° °     finding a palindrome of length 6,
 1 0 2 0 0 3 0 0      we store "3" and "mirror" the palindrome-length-table
a a b b a b b a b a b
                 ^    due to the fact that the previous two positions hold "0", 
 1 0 2 0 0 3 0 0 0    we can skip 2 pointer-positions and update the table
a a b b a b b a b a b
                   ^  now, we are done
 1 0 2 0 0 3 0 0 0 0

This means: As soon as we find a palindrome-position, we can infer some parts of the table.

Another example: aaaaaab

a a a a a a b
°^°
 1

a a a a a a b
° °^° °
 1 2 1        we can fill in the new "1" since we found a palindrome, thus mirroring the
              palindrome-length-table
a a A A a a b (capitals are just for emphasis)
     ^        at this point, we already know that there *must* be a palindrome of length
 1 2 1        at least 1, so we don't compare the two marked A's!, but start at the two 
              lower-case a's

My point is: As soon as we find palindromes, we may be able to mirror (at least a part of) the palindrome-length table and thus infer information about the new characters. This way, we can save comparisons.

like image 1
phimuemue Avatar answered Nov 11 '22 02:11

phimuemue