class Solution:
def validPalindrome(self, s: str) -> bool:
def is_palindrome_range(i, j):
while i < j:
if s[i] != s[j]:
return False
i += 1
j -= 1
return True
left, right = 0, len(s) - 1
while left < right:
if s[left] != s[right]:
# Try skipping either the left or the right character
return is_palindrome_range(left+1, right) or is_palindrome_range(left, right-1)
left += 1
right -= 1
return True
class Solution {
public:
bool isPalindromeRange(const std::string& s, int i, int j) {
while (i < j) {
if (s[i] != s[j]) return false;
++i;
--j;
}
return true;
}
bool validPalindrome(std::string s) {
int left = 0, right = s.size() - 1;
while (left < right) {
if (s[left] != s[right]) {
return isPalindromeRange(s, left+1, right) || isPalindromeRange(s, left, right-1);
}
++left;
--right;
}
return true;
}
};
class Solution {
public boolean validPalindrome(String s) {
int left = 0, right = s.length() - 1;
while (left < right) {
if (s.charAt(left) != s.charAt(right)) {
return isPalindromeRange(s, left + 1, right) || isPalindromeRange(s, left, right - 1);
}
left++;
right--;
}
return true;
}
private boolean isPalindromeRange(String s, int i, int j) {
while (i < j) {
if (s.charAt(i) != s.charAt(j)) return false;
i++;
j--;
}
return true;
}
}
var validPalindrome = function(s) {
function isPalindromeRange(i, j) {
while (i < j) {
if (s[i] !== s[j]) return false;
i++;
j--;
}
return true;
}
let left = 0, right = s.length - 1;
while (left < right) {
if (s[left] !== s[right]) {
return isPalindromeRange(left + 1, right) || isPalindromeRange(left, right - 1);
}
left++;
right--;
}
return true;
};
Given a string s
, determine if it can become a palindrome after deleting at most one character. A palindrome is a string that reads the same forwards and backwards. You may only remove one character, or none at all. The function should return true
if it's possible to make s
a palindrome with at most one deletion, and false
otherwise.
s
consists of lowercase letters and may be up to 105 characters long.true
if possible, false
if not.The classic way to check if a string is a palindrome is to use two pointers, one starting at the beginning and one at the end, comparing characters as they move towards the center. If all characters match, it's a palindrome.
The twist here is that you are allowed to remove at most one character. That means, if you find a mismatch, you have two choices: skip the character on the left or skip the character on the right, and check if the remaining substring is a palindrome. If either option works, the answer is true
.
Brute-forcing by removing every character one-by-one and checking for a palindrome would be too slow for large strings. Instead, we can optimize by only checking the two possible substrings when we find the first mismatch.
left
at the start of the string and right
at the end.
left < right
, compare s[left]
and s[right]
.
left
or right
character:
s[left+1:right+1]
is a palindrome.s[left:right]
is a palindrome.true
.true
. Otherwise, return false
.
Let's use the example s = "abca"
:
left = 0
, right = 3
. s[0] = 'a'
, s[3] = 'a'
. They match, move pointers inwards.left = 1
, right = 2
. s[1] = 'b'
, s[2] = 'c'
. Mismatch!'b'
(left+1
): Check if "ca"
is a palindrome. It's not.'c'
(right-1
): Check if "ba"
is a palindrome. It's not.s[1:3] = "bc"
(not palindrome)s[0:2] = "ab"
(not palindrome)s[2:3] = "c"
and s[1:2] = "b"
, both are palindromes because a single character is always a palindrome. So, the function would return true
."abca"
a palindrome by removing either 'b'
or 'c'
.O(n^2)
time and O(n)
space per check (for substring).
O(n)
).O(n)
total).O(n)
O(1)
(if implemented using indices, not slicing substrings).
This problem is a great example of how a small twist (allowing one removal) changes the classic palindrome check. By using a two-pointer technique and only checking the two possible substrings at the point of mismatch, we achieve an efficient O(n)
solution. The key insight is that only one removal is allowed, so we only need to check two possible cases when a mismatch occurs, making the approach both elegant and optimal.