Problem: this year on October 2, 2001, the date in MMDDYYYY format will be a palindrome (same forwards as backwards). 10/02/2001 when was the last date that this occurred on? (see if you can do it in your head!)
Solution
olution: we know the year has to be less than 2001 since we already have the palindrome for 10/02. it can’t be any year in 1900 because that would result in a day of 91. same for 1800 down to 1400. it could be a year in 1300 because that would be the 31st day. so whats the latest year in 1300 that would make a month? at first i thought it would be 1321, since that would give us the 12th month, but we have to remember that we want the maximum year in the 1300 century with a valid month, which would actually be 1390, since 09/31 is a valid date.
but of course, a question like this wouldn’t be complete without an aha factor. and of course, there are not 31 days in september, only 30. so we have to go back to august 08 which means the correct date would be 08/31/1380.
palindromes also offer another great string question. write a function that tests for palindromes bool isPalindrome( char* pStr )
if you start a pointer at the beginning and the end of the string and keep comparing characters while moving the pointers closer together, you can test if the string is the same forwards and backwards. notice that the pointers only have to travel to the middle, not all the way to the other end (to reduce redundancy).
thanks to tom for sending me this one! congrats on the wedding…
💡Strategies for Solving This Problem
String Palindrome Check
This is a warm-up question but don't underestimate it. I've seen people fail on edge cases.
The Basic Approach
Two pointers: one at start, one at end. Compare characters moving inward. If mismatch, not a palindrome.
O(n) time, O(1) space. This is the expected solution.
Common Variations
Ignore non-alphanumeric: "A man, a plan, a canal: Panama" → true
Case insensitive: "Racecar" → true
Find longest palindrome: Much harder (see separate problem)
Minimum edits to make palindrome: DP problem
Don't Overcomplicate
I've seen people try to reverse the string and compare. Works but uses O(n) extra space and shows you don't know the two-pointer pattern.
Edge Cases That Trip People Up
Empty string (usually true by convention)
Single character (true)
Special characters and spaces
Unicode characters (depends on requirements)
✅Solution
Solution: Two Pointers
function isPalindrome(s) {
let left = 0;
let right = s.length - 1;
while (left < right) {
if (s[left] !== s[right]) {
return false;
}
left++;
right--;
}
return true;
}
// Tests
console.log(isPalindrome("racecar")); // true
console.log(isPalindrome("hello")); // false
console.log(isPalindrome("")); // true
console.log(isPalindrome("a")); // true
console.log(isPalindrome("ab")); // false
With Alphanumeric Only + Case Insensitive
function isPalindromeAlphanumeric(s) {
// Clean string: remove non-alphanumeric, lowercase
const cleaned = s.toLowerCase().replace(/[^a-z0-9]/g, '');
let left = 0;
let right = cleaned.length - 1;
while (left < right) {
if (cleaned[left] !== cleaned[right]) {
return false;
}
left++;
right--;
}
return true;
}
console.log(isPalindromeAlphanumeric("A man, a plan, a canal: Panama"));
// true
console.log(isPalindromeAlphanumeric("race a car"));
// false
Without Extra Space (Skip Invalid Characters)
function isPalindromeNoExtraSpace(s) {
let left = 0;
let right = s.length - 1;
function isAlphanumeric(char) {
return /[a-z0-9]/i.test(char);
}
while (left < right) {
// Skip non-alphanumeric from left
while (left < right && !isAlphanumeric(s[left])) {
left++;
}
// Skip non-alphanumeric from right
while (left < right && !isAlphanumeric(s[right])) {
right--;
}
// Compare (case insensitive)
if (s[left].toLowerCase() !== s[right].toLowerCase()) {
return false;
}
left++;
right--;
}
return true;
}
console.log(isPalindromeNoExtraSpace("A man, a plan, a canal: Panama"));
// true
This version is O(1) space because we don't create a cleaned string.
Recursive Solution (Not Recommended)
function isPalindromeRecursive(s, left = 0, right = s.length - 1) {
// Base case
if (left >= right) return true;
// Check current pair
if (s[left] !== s[right]) return false;
// Recurse inward
return isPalindromeRecursive(s, left + 1, right - 1);
}
console.log(isPalindromeRecursive("racecar")); // true
This works but uses O(n) call stack space. The iterative version is better.
Complexity
Time: O(n) - Check each character once
Space: O(1) - Only pointer variables (if not creating cleaned string)
With cleaning: O(n) space for cleaned string
Common Mistakes
Reversing and comparing: Works but uses O(n) space unnecessarily
Not handling empty string: Should return true
Not considering case sensitivity: Ask interviewer!
Off-by-one errors: Make sure left < right, not left <= right