Palindrome Permutations

This was kind of a weird problem, but the solution was kind of fun to write. Given a string, determine if it’s a palindrome and then write out all the possible permutations of palindromes that string potentially would have.

Here’s my solution:

import collections
import itertools

def palinpermute(s):
    s = s.replace(" ", "")
    c = collections.Counter(s)

    pivot = ''
    for k, v in c.iteritems():
        if v % 2 != 0:
            if not pivot:
                pivot = k
                return (False, [])

    newStr = ""
    for k, v in c.iteritems():
        if k != pivot:
            newStr += k*(v/2)

    palins = list()
    for c in itertools.permutations(newStr):
        palins.append("".join(c) + pivot + "".join(reversed(c)))

    return (True, palins)

Like a lot of the other solutions to string problems, we’re back to using the Counter again. In this case we use it to make certain that for each character, there has to be a matching one. If there isn’t a matching one, choose that character as a pivot point for our palindrome. Once we’ve selected a pivot point, there can’t be another one, so just return False and an empty list if we find one.

This next part is probably not obvious:

    newStr = ""
    for k, v in c.iteritems():
        if k != pivot:
            newStr += k*(v/2)

This generates a half of a palindrome which we’re going to use to find all of the permutations. If we had the palindrome tacocat, we would end up with a string like act here. When we call itertools.permutations(), that’s going to come up with a list which looks like [('a', 'c', 't'), ('a', 'c', 't'), ('c', 'a', 't'), ('t', 'a', 'c'), ('c', 't', 'a'), ('t', 'c', 'a')]. Now it’s just a simple matter of joining each of these lists into new strings around our pivot point (if we have one), and we’ve found each of the potential palindromes.

The runtime complexity here comes down to how itertools.permutations() works. The permutations come out in lexigraphical sort order, so that’s at least n*log(n) average. Behind the scenes it’s doing something more akin to itertools.product() and filtering out repeated results, which means this can get kind of ugly really quickly from a performance standpoint.

I’m sure there are some interviewers out there who might think using itertools.permutations() feels like cheating. My take on it when I have interviewed candidates is that with very few exceptions it’s fair game to use parts of any standard library for any given programming language. Regardless, it’s not that hard to write some kind of recursive function which generates the same list if the interviewer is demanding it.