Valid Palindrome — Solution in Python, Java & C++
Valid Palindrome solution explained: step-by-step approach, complexity and code in Python, Java, C++ and JavaScript. An easy problem.
Valid Palindrome is an easy coding problem on strings and two pointers, asked in HCL, Spotify, Epic Systems and Mphasis interviews.
- Difficulty: Easy
- Topics: Strings, Two Pointers
- Asked at: HCL, Spotify, Epic Systems, Mphasis, Tech Mahindra
- Time limit: 2 s
- Memory limit: 256 MB
- Languages: JavaScript, TypeScript, Python, Java, C++, C, C#, Go, Kotlin, Swift, Rust, PHP and Ruby
Problem statement
A phrase is a palindrome if, after converting all uppercase letters to lowercase and removing all non-alphanumeric characters, it reads the same forward and backward.
Given a string s, return true if it is a palindrome, or false otherwise.
Example 1
Input: s = "A man, a plan, a canal: Panama"
Output: true
Explanation: "amanaplanacanalpanama" is a palindrome.
Example 2
Input: s = "race a car"
Output: false
Explanation: "raceacar" is not a palindrome.
Constraints
0 <= s.length <= 40s consists of printable ASCII characters.
Hints for Valid Palindrome
Hint 1
Normalize first: lowercase and strip everything that is not a letter or digit.
Hint 2
Two pointers from both ends avoid building the reversed copy.
How to solve Valid Palindrome
Do not build a cleaned copy of the string — walk it from both ends at once and simply skip anything that is not alphanumeric. Compare the surviving characters case-insensitively; the first mismatch settles it.
Approach
- Put
lat the start andrat the end. - Advance
lrightwards past any non-alphanumeric character, andrleftwards likewise. - Compare the two characters after lowercasing; a mismatch means it is not a palindrome.
- Move both pointers inward and repeat until they meet.
Why it works
Filtering and lowercasing are per-character decisions, so they can be applied on the fly rather than in a separate pass — which is what keeps the extra space constant. The two-pointer comparison is exactly the definition of a palindrome applied to the filtered sequence: position i from the front must equal position i from the back, and the skipping ensures both pointers always land on characters that survive the filter.
Complexity
- Time —
O(n) - Space —
O(1)
Pitfalls
- Keep the skip loops bounded by
l < r, or a string of only punctuation runs off the end. - Digits count as alphanumeric, not just letters.
- Lowercase both sides before comparing.
- An empty string, or one with no alphanumeric characters at all, is a palindrome.
Reference solution
Python
def isPalindrome(s: str) -> bool:
c = [ch.lower() for ch in s if ch.isalnum()]
return c == c[::-1]Java
public static boolean isPalindrome(String s) {
int l = 0, r = s.length() - 1;
while (l < r) {
while (l < r && !Character.isLetterOrDigit(s.charAt(l))) l++;
while (l < r && !Character.isLetterOrDigit(s.charAt(r))) r--;
if (Character.toLowerCase(s.charAt(l)) != Character.toLowerCase(s.charAt(r))) return false;
l++;
r--;
}
return true;
}C++
bool isPalindrome(string s) {
int l = 0, r = (int) s.size() - 1;
while (l < r) {
while (l < r && !isalnum((unsigned char) s[l])) l++;
while (l < r && !isalnum((unsigned char) s[r])) r--;
if (tolower((unsigned char) s[l]) != tolower((unsigned char) s[r])) return false;
l++;
r--;
}
return true;
}JavaScript
var isPalindrome = function(s) {
const c = s.toLowerCase().replace(/[^a-z0-9]/g, "");
for (let i = 0, j = c.length - 1; i < j; i++, j--) {
if (c[i] !== c[j]) return false;
}
return true;
};Also on the editorial tab: C, C#, Go, Kotlin, PHP, Ruby, Rust, Swift, TypeScript.
All 515 strings problems · the whole catalogue
Learn the technique: Strings · Two Pointers Technique