A palindrome is a string, number, or sequence that reads the same forward and backward.
Examples include:
racecar
level
madam
1221
while:
hello
algorithm
1234
are not palindromes.
Palindrome checking is a simple algorithmic problem, but it is particularly useful for learning Two Pointers, string traversal, recursion, normalization, and space optimization.
Basic idea
Consider:
racecar
Reversing it gives:
racecar
so it is a palindrome.
For:
hello
we get:
olleh
which is different.
Method 1: Reverse the string
The simplest solution creates a reversed copy and compares it with the original.
function isPalindrome(value: string): boolean {
const reversed = value.split("").reverse().join("");
return value === reversed;
}
Its complexity is approximately:
Time Complexity: O(n)
Space Complexity: O(n)
because a reversed representation must be created.
Method 2: Two Pointers
A more memory-efficient solution places one pointer at each end of the string.
r a c e c a r
↑ ↑
L R
Compare the two characters. If they match, move both pointers toward the center.
left++
right--
If any pair differs, the string is not a palindrome.
Pseudocode:
left = 0
right = length - 1
while left < right:
if string[left] != string[right]:
return false
left++
right--
return true
TypeScript implementation
function isPalindrome(value: string): boolean {
let left = 0;
let right = value.length - 1;
while (left < right) {
if (value[left] !== value[right]) {
return false;
}
left++;
right--;
}
return true;
}
Complexity:
Time Complexity: O(n)
Space Complexity: O(1)
This is the standard interview-friendly solution.
Why only half of the string?
Every comparison checks two symmetric positions.
Once the pointers meet or cross, every relevant pair has already been tested.
The center character in an odd-length palindrome does not need a partner.
Ignoring spaces and punctuation
Real problems often use input such as:
A man, a plan, a canal: Panama
After removing non-alphanumeric characters and converting to lowercase:
amanaplanacanalpanama
it becomes a palindrome.
One solution is normalization:
function normalize(value: string): string {
return value
.toLowerCase()
.replace(/[^a-z0-9]/g, "");
}
Then apply the two-pointer algorithm.
Checking without creating a normalized copy
We can also skip punctuation while moving the pointers.
function isAlphaNumeric(char: string): boolean {
return /[a-z0-9]/i.test(char);
}
function isPalindrome(value: string): boolean {
let left = 0;
let right = value.length - 1;
while (left < right) {
while (left < right && !isAlphaNumeric(value[left])) {
left++;
}
while (left < right && !isAlphaNumeric(value[right])) {
right--;
}
if (
value[left].toLowerCase() !==
value[right].toLowerCase()
) {
return false;
}
left++;
right--;
}
return true;
}
This retains the important two-pointer pattern without constructing another full string.
Numeric palindromes
Numbers can also be palindromes:
121
1221
4554
The simplest solution converts the number to a string.
function isNumberPalindrome(value: number): boolean {
const text = String(value);
return text === text.split("").reverse().join("");
}
Another solution reverses the digits mathematically.
function isNumberPalindrome(value: number): boolean {
if (value < 0) {
return false;
}
const original = value;
let reversed = 0;
while (value > 0) {
const digit = value % 10;
reversed = reversed * 10 + digit;
value = Math.floor(value / 10);
}
return original === reversed;
}
Negative integers are generally not treated as palindromes because the minus sign appears on only one side.
Recursive solution
Palindrome checking can also be expressed recursively.
function isPalindromeRecursive(
value: string,
left = 0,
right = value.length - 1
): boolean {
if (left >= right) {
return true;
}
if (value[left] !== value[right]) {
return false;
}
return isPalindromeRecursive(
value,
left + 1,
right - 1
);
}
The time complexity remains O(n), but recursion consumes stack space, producing approximately O(n) additional space.
The iterative two-pointer version is therefore usually preferable.
Almost Palindrome
A common extension asks:
Can the string become a palindrome after deleting at most one character?
For example:
abca
can become a palindrome by removing either b or c appropriately.
When the first mismatch appears, test two possibilities:
skip left
skip right
function isRangePalindrome(
value: string,
left: number,
right: number
): boolean {
while (left < right) {
if (value[left] !== value[right]) {
return false;
}
left++;
right--;
}
return true;
}
function validPalindrome(value: string): boolean {
let left = 0;
let right = value.length - 1;
while (left < right) {
if (value[left] !== value[right]) {
return (
isRangePalindrome(value, left + 1, right) ||
isRangePalindrome(value, left, right - 1)
);
}
left++;
right--;
}
return true;
}
Why this problem matters
Palindrome checking is the foundation for more advanced problems including:
- Longest Palindromic Substring
- Palindromic Subsequence
- Palindrome Partitioning
- Minimum Insertions for Palindrome
- Valid Palindrome
- Almost Palindrome
The symmetric comparison pattern appears repeatedly in these problems.
Two Pointers as a general technique
The technique is much broader than palindrome problems.
Two Pointers also appears in problems such as:
- Pair Sum in sorted arrays
- Removing duplicates
- Container With Most Water
- Partitioning
- Array merging
- Several sequence-processing problems
Palindrome checking is one of the cleanest introductions to the technique.
Unicode considerations in JavaScript
JavaScript string indexing is based on UTF-16 code units, which means some Unicode symbols and emoji may occupy more than one unit.
For ASCII-focused interview problems this is normally irrelevant.
For Unicode-aware software, you may need a representation such as:
const chars = Array.from(value);
or more specialized Unicode processing depending on the requirements.
Case sensitivity
Whether:
Level
is considered a palindrome depends on the rules.
Case-sensitive comparison says it is not, while normalizing to lowercase gives:
level
which is a palindrome.
The normalization rules should therefore be part of the problem definition.
Common interview question
A typical problem says:
Determine whether a string is a palindrome while ignoring punctuation, spaces, and letter case.
Example:
Input:
A man, a plan, a canal: Panama
Output:
true
A strong solution uses:
Two Pointers
+ Skip non-alphanumeric characters
+ Case-insensitive comparison
and achieves:
Time: O(n)
Space: O(1)
without building a normalized copy.
Common mistakes
Unclear normalization rules
Always determine whether spaces, punctuation, case, and Unicode should matter.
Unnecessary extra memory
Reversing the string is valid, but an interviewer may specifically ask for constant extra space.
Incorrect loop condition
A common and clean condition is:
left < right
Forgetting empty and single-character strings
Both are generally palindromes:
"" → true
"a" → true
Reverse vs. Two Pointers
Reverse-based solution:
Time: O(n)
Space: O(n)
Two-pointer solution:
Time: O(n)
Space: O(1)
For algorithmic learning and technical interviews, Two Pointers is normally the more useful approach.
Conclusion
A palindrome reads identically from both directions.
The standard algorithmic solution uses two pointers:
left → beginning
right → end
compare
↓
move inward
with:
Time Complexity: O(n)
Space Complexity: O(1)
The value of this problem goes beyond recognizing words like racecar. It provides a clean introduction to symmetric reasoning, Two Pointers, normalization, edge cases, and memory-efficient string processing.