It's possible to solve this problem by messing around with the string's characters in a given index. The trick is to use string-ref
wisely. Here, let me give you some hints pointing to a solution that will work with the beginner's language :
; this is the main procedure
(define (palindrome? s)
; it uses `loop` as a helper
(loop <???> <???> <???>))
; loop receives as parameters:
; `s` : the string
; `i` : the current index, starting at 0
; `n` : the string's length
(define (loop s i n)
(cond (<???> ; if `i` equals `n`
<???>) ; then `s` is a palindrome
(<???> ; if the char at the current index != its opposite (*)
<???>) ; then `s` is NOT a palindrome
(else ; otherwise
(loop <???> <???> <???>)))) ; advance the recursion over `i`
Of course, the interesting part is the one marked with (*)
. Think of it, a string is a palindrome if the char at the 0
index equals the char at the n-1
index (n
being the string's length) and the char at the 1
index equals the char at the n-2
index, and so on. In general, if it's true that the char at the i
index equals the char at the n-i-1
index (its "opposite") for all i
, then we can conclude that the string is a palindrome - but if a single pair of opposite chars is not equal to each other, then it's not a palindrome.
As a further optimization, notice that you don't need to traverse the whole string, it's enough to test the characters up to the half of the string's length (this is explained in Chris' answer) - intuitively, you can see that if the char at i
equals the char at n-i-1
, then it follows that the char at n-i-1
equals the char at i
, so there's no need to perform the same test two times.
Try to write the procedures on your own, and don't forget to test them:
(palindrome? "")
=> #t
(palindrome? "x")
=> #t
(palindrome? "axa")
=> #t
(palindrome? "axxa")
=> #t
(palindrome? "axc")
=> #f
(palindrome? "axca")
=> #f
(palindrome? "acxa")
=> #f
(palindrome? "axcta")
=> #f