## Identifying Palindromes

### March 31, 2015

It is easy to determine if an array is a palindrome: Start with pointers to the first and last elements of the array. If the two elements are the same, increment the left pointer and decrement the right pointer. Stop with failure if at any point the two elements differ. Stop with success when the two pointers cross:

`(define (palindrome? xv)`

(let ((len (vector-length xv)))

(let loop ((left 0) (right (- len 1)))

(cond ((< right left) #t)

((not (equal? (vector-ref xv left)

(vector-ref xv right))) #f)

(else (loop (+ left 1) (- right 1)))))))

`> (palindrome? (vector 1 2 3 4 5 6 7))`

#f

> (palindrome? (vector 1 2 3 4 3 2 1))

#t

Determining if a list is a palindrome is harder because the length of the list is now known in advance. We use the tortoise-and-hare algorithm to find the middle of the list, accumulating the elements of the front half of the list while the hare is still in the list and comparing the saved front half of the list to the back half of the list once the hare has reached the end:

`(define (palindrome? xs)`

(let loop ((h xs) (t xs) (front (list)))

(cond ((null? t) #t)

((pair? h)

(if (pair? (cdr h))

(loop (cddr h) (cdr t)

(cons (car t) front))

(loop (cdr h) (cdr t) front)))

((equal? (car t) (car front))

(loop h (cdr t) (cdr front)))

(else #f))))

`> (palindrome? (list 1 2 3 4 5 6 7))`

#f

> (palindrome? (list 1 2 3 4 3 2 1))

#t

This is clearly O(*n*), since the tortoise takes one step each time through the loop. The building half of the algorithm occurs in the second `cond`

clause, the comparison occurs in the third `cond`

clause, and the other two clauses report results. The space complexity is O(*n* /2), which is the space required to save the front half of the list. If you don’t mind scrambling the list, you could reverse the second half of the list after the hare reaches the end, then compare the front half of the list to the reversed back half of the list, reducing the space complexity to O(1).

You can run the program at http://ideone.com/22EEG0.

Note that integer division is used, as the middle element of an array of uneven length always satisfies the palindrome condition.

A mindless transcription of the model hare and tortoise to Python:

Sorry about the mis-indentations. Something in the copy-and-paste.

Here’s a list reversing solution, with the list reverse done in place and the correct order restored afterwards:

Palindrome Check for Arrays:

importjava.util.LinkedList;importjava.util.List;importjava.util.Scanner;publicclassListPalidrome {privatestaticList myList;publicstaticvoidmain(String[] args) {myList =

newLinkedList();System.out.println(“enter the elements in list, enter e to stop”);

Scanner sc =

newScanner(System.in);while(sc.hasNextInt()) {myList.add(sc.nextInt());

}

sc.close();

System.out.println(isPalidrome(myList));

}

privatestaticbooleanisPalidrome(List myList) {// input is empty or single element, return true

if(myList.isEmpty() || myList.size() == 1) {returntrue;}

// use an aux list for storing first half of the list

List auxList =

newLinkedList();intlen = myList.size();intt = 0;// tortoiseinth = 0;// harewhile(h < len – 1) {// add tortoise to front of auxList

auxList.add(0, myList.get(t));

t++;

// double increment hare

h += 2;

}

//if length is odd, skip the middle element from comparison

if(len % 2 != 0) t++;//compare tortoise journey to auxList

intk = 0;while(t < len) {if(myList.get(t++) != auxList.get(k++))returnfalse;}

returntrue;}

}

Code Formatted by ToGoTutor

[…] of my favorite sites Programming Praxis recently had an entry on detecting palindromes. Even if you’re not interested in palindromes, […]

import sys

def check_palindrom(input_list):

if len(input_list) == 1:

return “YES, A Palindrom”

else:

mid = len(input_list)/2

print “MID=”, mid

for i in range(mid):

if (input_list[i] != input_list[len(input_list)-1-i]):

return “No, Not a Palindrom”

else:

continue

return “YES, A Palindrom”

print “Enter the array element with space seperated. Press Enter when done”

input_array = raw_input()

input_list = input_array.split()

print len(input_list)

input_list = [sys.exit(1) if len(input_list)< 1 else (j) for j in input_list]

print input_list

print check_palindrom(input_list

A C++ version that works with std::vector, std::list or any class that supports begin, end, rbegin, and rend. (Since std::list is doubly-linked, it makes things easier.)

This version uses std::mismatch. In essence this is similar to the previous version I posted, except we have to precalculate the end condition using c.size and std::advance. Not a big deal for std::vector, but not good for std::list. Some implementations of std::list maintain a size member variable making c.size O(1) instead of O(n), so the impact varies.