What Is a Palindrome String?
A palindrome is a sequence that reads the same forward and backward. A palindrome string therefore has the same character order when viewed from either direction.
"level" → palindrome
"radar" → palindrome
"hello" → not a palindrome
Palindrome problems are useful for learning string traversal, character comparison, two-pointer techniques, and the practical use of data structures. They are also common coding interview exercises because the basic problem can be extended with additional rules such as ignoring spaces, punctuation, or letter casing.
How to Recognize a Palindrome
A string is a palindrome when the first character matches the last, the second character matches the second-to-last, and so on until the middle of the string is reached.
String: R A C E C A R
↑ ↑
first last
R = R
↑ ↑
A A
A = A
↑ ↑
C C
C = C
Result: palindrome
This observation leads directly to the two-pointer approach, which compares characters from both ends and moves toward the center.
Palindrome Check with Two Pointers
The two-pointer technique is one of the most efficient and commonly taught approaches. One pointer starts at the beginning of the string and another starts at the end. If the characters differ, the string cannot be a palindrome.
function isPalindrome(text) {
let left = 0;
let right = text.length - 1;
while (left < right) {
if (text[left] !== text[right]) {
return false;
}
left++;
right--;
}
return true;
}
console.log(isPalindrome("level"));
// true
console.log(isPalindrome("hello"));
// false
How the Two-Pointer Method Works
Consider the word "level". The pointers initially
point to the first and last characters.
l e v e l
↑ ↑
L R
l === l
↑ ↑
L R
e === e
↑
M
Once the pointers meet or cross, every required pair has matched, so the string is a palindrome.
Why Only Half the String Needs to Be Checked
Every comparison checks two characters at the same time. Once the pointers reach the middle, all mirrored pairs have already been verified. There is no need to compare the second half independently.
For a string of length n, the algorithm performs
at most about n / 2 comparisons. In Big O notation,
this is still O(n) time.
Palindrome Check Using String Reversal
Another simple approach is to reverse the string and compare the result with the original string. If both strings are identical, the input is a palindrome.
function isPalindrome(text) {
const reversed = text.split("").reverse().join("");
return text === reversed;
}
console.log(isPalindrome("racecar"));
// true
console.log(isPalindrome("developer"));
// false
This approach is concise and easy to understand. However, it creates an additional array and reversed string, so it uses more auxiliary memory than a direct comparison with two pointers.
Ignoring Letter Case
Some palindrome problems treat uppercase and lowercase letters as equivalent. In that case, normalize the input before performing the comparison.
function isPalindrome(text) {
text = text.toLowerCase();
let left = 0;
let right = text.length - 1;
while (left < right) {
if (text[left] !== text[right]) {
return false;
}
left++;
right--;
}
return true;
}
console.log(isPalindrome("Level"));
// true
Whether case should be ignored is a requirement of the specific problem. It should not be assumed unless the input rules call for it.
Ignoring Spaces and Punctuation
A common variation asks whether a sentence is a palindrome while ignoring spaces, punctuation, and letter casing. For example, a phrase may be considered a palindrome after keeping only alphanumeric characters.
function isPalindromePhrase(text) {
const normalized = text
.toLowerCase()
.replace(/[^a-z0-9]/g, "");
let left = 0;
let right = normalized.length - 1;
while (left < right) {
if (normalized[left] !== normalized[right]) {
return false;
}
left++;
right--;
}
return true;
}
console.log(
isPalindromePhrase("A man, a plan, a canal: Panama")
);
// true
The normalization step changes the problem slightly. Instead of checking the original string directly, the algorithm checks a cleaned representation containing only the characters relevant to the comparison.
Two Pointers Without Creating a New String
If memory usage matters, the input can be examined directly while skipping characters that should not participate in the palindrome comparison. This avoids creating a complete normalized copy.
function isPalindromePhrase(text) {
let left = 0;
let right = text.length - 1;
while (left < right) {
while (
left < right &&
!/[a-z0-9]/i.test(text[left])
) {
left++;
}
while (
left < right &&
!/[a-z0-9]/i.test(text[right])
) {
right--;
}
if (
text[left].toLowerCase() !==
text[right].toLowerCase()
) {
return false;
}
left++;
right--;
}
return true;
}
console.log(
isPalindromePhrase("A man, a plan, a canal: Panama")
);
// true
Palindrome Using a Stack
A stack can also be used to check whether a string is a palindrome. Because a stack returns elements in reverse order, pushing all characters and then popping them allows the reversed sequence to be compared with the original sequence.
function isPalindrome(text) {
const stack = [];
for (const char of text) {
stack.push(char);
}
for (const char of text) {
if (char !== stack.pop()) {
return false;
}
}
return true;
}
console.log(isPalindrome("level"));
// true
console.log(isPalindrome("hello"));
// false
This approach demonstrates the relationship between palindrome problems and the LIFO behavior of stacks. It is useful for learning data structures, although the two-pointer method generally requires less additional memory for this specific problem.
Palindrome with Recursion
A palindrome can also be checked recursively by comparing the first and last characters, then recursively checking the substring between them.
function isPalindrome(text, left = 0, right = text.length - 1) {
if (left >= right) {
return true;
}
if (text[left] !== text[right]) {
return false;
}
return isPalindrome(text, left + 1, right - 1);
}
console.log(isPalindrome("racecar"));
// true
The recursive solution mirrors the definition of a palindrome, but it uses the JavaScript call stack for recursive calls. An iterative two-pointer solution is generally easier to control for very large inputs.
Handling Empty and Single-Character Strings
An empty string and a single-character string are both palindromes because there is no pair of characters that violates the palindrome condition.
console.log(isPalindrome(""));
// true
console.log(isPalindrome("a"));
// true
console.log(isPalindrome("aa"));
// true
console.log(isPalindrome("ab"));
// false
The two-pointer loop naturally handles these cases because the pointers either start at the same position or meet without finding a mismatch.
Palindrome Numbers as a Related Problem
The same mirrored-comparison idea can be applied to numbers. A number such as
121 reads the same in both directions. One
approach is to convert the number to a string, while another reverses the digits
mathematically.
function isPalindromeNumber(number) {
const text = String(number);
return text === text.split("").reverse().join("");
}
console.log(isPalindromeNumber(121));
// true
console.log(isPalindromeNumber(123));
// false
Number-palindrome problems may have additional requirements, such as avoiding string conversion. In those cases, the algorithm needs to work directly with the digits.
Comparing Palindrome Approaches
| Approach | Time | Extra Space | Useful For |
|---|---|---|---|
| Two pointers | O(n) | O(1) auxiliary space | Efficient palindrome checks |
| Reverse and compare | O(n) | O(n) | Simple implementations |
| Stack | O(n) | O(n) | Learning LIFO-based solutions |
| Recursion | O(n) | O(n) call stack | Understanding recursive logic |
A Useful Interview Pattern
When a problem asks whether two ends of a sequence have matching values, consider whether a two-pointer approach can reduce unnecessary work. For palindrome strings, the comparison naturally moves inward from both boundaries.
left → ← right
[a][b][c][d][c][b][a]
Compare:
a with a
b with b
c with c
Stop at the middle.
This pattern is useful beyond strings. Similar left-and-right comparisons appear in sorted arrays, pair-search problems, partitioning algorithms, and other sequence-based challenges.
Common Mistakes
- Comparing every character with every other character and creating unnecessary O(n²) work.
- Forgetting to move both pointers after a successful comparison.
- Using the wrong normalization rules for spaces, punctuation, or case.
- Treating an empty or single-character string as invalid without checking the problem requirements.
- Creating a reversed string when the problem specifically requires constant auxiliary space.
Complexity Analysis
For a string containing n characters, the
two-pointer solution performs at most approximately n / 2
comparisons. Therefore, its time complexity is O(n), while its auxiliary space is O(1)
when the original input can be accessed directly.
Approaches that create a reversed string, normalized copy, or stack require additional memory proportional to the input size.
Key Takeaways
- A palindrome reads the same from left to right and right to left.
- The two-pointer technique compares mirrored characters efficiently.
- A direct two-pointer check runs in O(n) time with O(1) auxiliary space.
- Reversing and comparing is simple but requires additional memory.
- A stack can demonstrate how LIFO ordering helps solve palindrome problems.
- Case, spaces, and punctuation should be handled according to the problem requirements.
- Empty and single-character strings are normally palindromes.