Talentd
FleetCode
Make and follow sheets.Sign in

Valid Palindrome II solution and explanation

EasyGreedyStringTwo Pointers6 min read44.7% acceptanceUpdated 9 Apr 2026
Valid Palindrome II - Leetcode 680 - PythonNeetCode · 7:46 · 82K viewsWatch on YouTube
9 more videos on this problem
  1. Valid Palindrome II - Leetcode 680 - PythonNeetCode · 7:46 · 82K views
  2. Valid Palindrome 2 (LeetCode 680) | Simplified solution with basics | Visuals AnimationsNikhil Lohia · 12:37 · 17K views
  3. Valid Palindrome II - LeetCode 680 - JavaScriptAlgoJS · 4:26 · 1K views
  4. LeetCode 680 | Valid Palindrome II | Greedy Algorithm Explained (Java)Xavier Elon · 7:35 · 1K views
  5. 680. Valid Palindrome II - LeetCode JavaScriptBecoming A Better Dev (with David) · 8:38 · 658 views
  6. LeetCode - 680. Valid Palindrome II | Two Pointers Technique | JavaOrkhan Gasanov · 3:52 · 470 views
  7. 680. Valid Palindrome II | LEETCODE EASYcode Explainer · 6:34 · 291 views
  8. 680. Valid Palindrome II | English | EasySimple Code - 단순코드 · 7:13 · 281 views
  9. Baozi Training Leetcode 680 solution: Valid Palindrome IIBaozi Training · 6:08 · 173 views
  10. LeetCode #680: Valid Palindrome II in Java | Brute Force vs Two Pointers O(n) - Interview Must-Know!Algo Ducky · 4:04 · 165 views

The problem

Given a string s, return true if the s can be palindrome after deleting at most one character from it.

Example 1:

Input: s = "aba"
Output: true

Example 2:

Input: s = "abca"
Output: true
Explanation: You could delete the character 'c'.

Example 3:

Input: s = "abc"
Output: false

Constraints:

  • 1 <= s.length <= 105
  • s consists of lowercase English letters.

Approach overview

Problem Overview: You are given a string s. The task is to determine whether it can become a palindrome after deleting at most one character. A palindrome reads the same forward and backward, so the challenge is detecting whether a single mismatch can be fixed by skipping one character.

This problem heavily relies on the two pointers pattern and careful string comparison. Instead of generating all possible deletions, you scan from both ends and react only when a mismatch appears.

Approach 1: Two Pointer Technique (O(n) time, O(1) space)

Use two pointers: left at the start of the string and right at the end. Move both pointers inward while characters match. When a mismatch appears, you get exactly one chance to delete a character. At that moment, check two possibilities: skip the left character (left + 1) or skip the right character (right - 1). If either remaining substring forms a palindrome, the answer is true.

The key insight is that only the first mismatch matters. After removing one character, the rest of the substring must already be a valid palindrome. This avoids brute-force deletion and keeps the scan linear. The algorithm performs a single pass over the string with at most one additional palindrome check, resulting in O(n) time and O(1) space. This pattern appears often in string problems that involve symmetry checks.

Approach 2: Recursive Two Pointers Method (O(n) time, O(n) recursion stack)

This variation applies the same idea but expresses the "skip one character" decision through recursion. Start with two pointers at the ends of the string. If characters match, recursively check the inner substring. When a mismatch occurs and deletion is still allowed, branch into two recursive calls: skip the left character or skip the right character.

A boolean flag tracks whether the deletion has already been used. Once the flag is consumed, further mismatches immediately fail. Although the total number of comparisons remains linear, recursive calls introduce stack usage up to O(n) space. This approach is easier to reason about conceptually because the recursive structure mirrors the palindrome definition.

Both approaches use the same core idea: a single mismatch can be corrected by removing one character. This greedy decision works because any valid solution must remove one of the two mismatching characters.

Recommended for interviews: The iterative two-pointer solution is the expected answer. It demonstrates mastery of the two pointers technique and achieves optimal O(n) time with constant space. Explaining the recursive variant can still help show deeper understanding of the decision process and the greedy nature of the first mismatch handling.

Approach 1: Two Pointer Technique

This approach uses the two-pointer technique to check if the string is a palindrome after removing at most one character. Start with two pointers at the beginning and end of the string. Move inward while the characters at these pointers are equal. If a mismatch occurs, there are two possibilities: either remove the character at the left pointer or the right pointer. If either results in a palindrome, then the string can be considered a valid palindrome after one deletion.

class Solution:
    def isPalindromeRange(self, s: str, i: int, j: int) -> bool:
        return all(s[k] == s[j] for k, j in zip(range(i, j), range(j, i, -1)))

    def validPalindrome(self, s: str) -> bool:
        left, right = 0, len(s) - 1
        while left < right:
            if s[left] != s[right]:
                return self.isPalindromeRange(s, left + 1, right) or self.isPalindromeRange(s, left, right - 1)
            left += 1
            right -= 1
        return True
class Solution {
    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;
    }
    public boolean validPalindrome(String s) {
        int left = 0;
        int 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;
    }
}
#include <string>
using namespace std;

class Solution {
public:
    bool isPalindromeRange(const string& s, int i, int j) {
        while (i < j) {
            if (s[i] != s[j]) return false;
            i++;
            j--;
        }
        return true;
    }
    bool validPalindrome(string s) {
        int left = 0;
        int 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;
    }
};
var validPalindrome = function(s) {
    let isPalindromeRange = (s, 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(s, left + 1, right) || isPalindromeRange(s, left, right - 1);
        }
        left++;
        right--;
    }
    return true;
};
#include <stdbool.h>
#include <string.h>

bool isPalindromeRange(char * s, int i, int j) {
    while (i < j) {
        if (s[i] != s[j]) return false;
        i++;
        j--;
    }
    return true;
}

bool validPalindrome(char * s) {
    int left = 0;
    int right = strlen(s) - 1;
    while (left < right) {
        if (s[left] != s[right]) {
            return isPalindromeRange(s, left + 1, right) || isPalindromeRange(s, left, right - 1);
        }
        left++;
        right--;
    }
    return true;
}
public class Solution {
    private bool IsPalindromeRange(string s, int i, int j) {
        while (i < j) {
            if (s[i] != s[j]) return false;
            i++;
            j--;
        }
        return true;
    }
    public bool ValidPalindrome(string s) {
        int left = 0;
        int right = s.Length - 1;
        while (left < right) {
            if (s[left] != s[right]) {
                return IsPalindromeRange(s, left + 1, right) || IsPalindromeRange(s, left, right - 1);
            }
            left++;
            right--;
        }
        return true;
    }
}

In the Python version, the solution uses a helper function to check if a segment of the string is a palindrome. We then handle mismatches by removing either the left or right character.

Complexity

Time Complexity: O(n)
Space Complexity: O(1).

Try this approach in the editor

Approach 2: Recursive Two Pointers Method

This approach uses recursion to accomplish the same task. When encountering the first differing pair of characters, we make two recursive calls: one ignoring the left character and one ignoring the right character. If either recursive call results in a valid palindrome, the whole string can be considered a valid palindrome after a single character deletion.

class Solution:
    def validPalindrome(self, s: str) -> bool:
        def helper(s, left, right, deleted):
            while left < right:
                if s[left] != s[right]:
                    if deleted:
                        return False
                    return helper(s, left + 1, right, True) or helper(s, left, right - 1, True)
                left += 1
                right -= 1
            return True
        return helper(s, 0, len(s) - 1, False)
class Solution {
    public boolean validPalindrome(String s) {
        return helper(s, 0, s.length() - 1, false);
    }
    private boolean helper(String s, int left, int right, boolean deleted) {
        while (left < right) {
            if (s.charAt(left) != s.charAt(right)) {
                if (deleted) return false;
                return helper(s, left + 1, right, true) || helper(s, left, right - 1, true);
            }
            left++;
            right--;
        }
        return true;
    }
}
#include <string>
using namespace std;

class Solution {
public:
    bool validPalindrome(string s) {
        return helper(s, 0, s.size() - 1, false);
    }
    bool helper(const string& s, int left, int right, bool deleted) {
        while (left < right) {
            if (s[left] != s[right]) {
                if (deleted) return false;
                return helper(s, left + 1, right, true) || helper(s, left, right - 1, true);
            }
            left++;
            right--;
        }
        return true;
    }
};
var validPalindrome = function(s) {
    function helper(s, left, right, deleted) {
        while (left < right) {
            if (s[left] !== s[right]) {
                if (deleted) return false;
                return helper(s, left + 1, right, true) || helper(s, left, right - 1, true);
            }
            left++;
            right--;
        }
        return true;
    }
    return helper(s, 0, s.length - 1, false);
};
#include <stdbool.h>
#include <string.h>

bool isPalindromeRange(char* s, int i, int j) {
    while (i < j) {
        if (s[i] != s[j]) return false;
        i++;
        j--;
    }
    return true;
}

bool validPalindromeHelper(char* s, int i, int j, bool deleted) {
    while (i < j) {
        if (s[i] != s[j]) {
            if (deleted) return false;
            return validPalindromeHelper(s, i + 1, j, true) || validPalindromeHelper(s, i, j - 1, true);
        }
        i++;
        j--;
    }
    return true;
}

bool validPalindrome(char* s) {
    return validPalindromeHelper(s, 0, strlen(s) - 1, false);
}
public class Solution {
    public bool ValidPalindrome(string s) {
        return Helper(s, 0, s.Length - 1, false);
    }

    private bool Helper(string s, int left, int right, bool deleted) {
        while (left < right) {
            if (s[left] != s[right]) {
                if (deleted) return false;
                return Helper(s, left + 1, right, true) || Helper(s, left, right - 1, true);
            }
            left++;
            right--;
        }
        return true;
    }
}

The Python solution combines recursion with two-pointer strategy by implementing a recursive helper function, with optional deletions permitted.

Complexity

Time Complexity: O(n)
Space Complexity: O(n) due to Python-like recursion limitations.

Try this approach in the editor

Approach 3: Two Pointers

We use two pointers to point to the left and right ends of the string, respectively. Each time, we check whether the characters pointed to by the two pointers are the same. If they are not the same, we check whether the string is a palindrome after deleting the character corresponding to the left pointer, or we check whether the string is a palindrome after deleting the character corresponding to the right pointer. If the characters pointed to by the two pointers are the same, we move both pointers towards the middle by one position, until the two pointers meet.

If we have not encountered a situation where the characters pointed to by the pointers are different by the end of the traversal, then the string itself is a palindrome, and we return true.

The time complexity is O(n), where n is the length of the string s. The space complexity is O(1).

function validPalindrome(s: string): boolean {
    const check = (i: number, j: number): boolean => {
        for (; i < j; ++i, --j) {
            if (s[i] !== s[j]) {
                return false;
            }
        }
        return true;
    };
    for (let i = 0, j = s.length - 1; i < j; ++i, --j) {
        if (s[i] !== s[j]) {
            return check(i + 1, j) || check(i, j - 1);
        }
    }
    return true;
}
func validPalindrome(s string) bool {
	check := func(i, j int) bool {
		for ; i < j; i, j = i+1, j-1 {
			if s[i] != s[j] {
				return false
			}
		}
		return true
	}
	for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
		if s[i] != s[j] {
			return check(i+1, j) || check(i, j-1)
		}
	}
	return true
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Two Pointer Technique

Time Complexity: O(n)
Space Complexity: O(1).

Recursive Two Pointers Method

Time Complexity: O(n)
Space Complexity: O(n) due to Python-like recursion limitations.

Two Pointers–

Complexity analysis

ApproachTimeSpaceWhen to Use
Two Pointer TechniqueO(n)O(1)Best general solution. Optimal for interviews and large strings because it uses constant extra memory.
Recursive Two PointersO(n)O(n)Useful for conceptual clarity or when explaining the skip decision recursively.

Frequently asked questions

Is Valid Palindrome II easy or hard?

LeetCode classifies Valid Palindrome II as an Easy problem. The difficulty mainly comes from recognizing that only one deletion is allowed and handling the first mismatch correctly using a two-pointer check.

How to solve Valid Palindrome II in O(n)?

Use two pointers starting at the beginning and end of the string. Move inward while characters match. On the first mismatch, check if either substring formed by skipping one character is a palindrome. Since only one deletion is allowed, the process stays linear with O(n) time.

What is the best approach for Valid Palindrome II?

The two pointer approach is the best solution. Start with pointers at both ends of the string and move inward while characters match. When a mismatch appears, check whether skipping either the left or right character produces a palindrome. This runs in O(n) time with O(1) extra space.

What data structure is used in Valid Palindrome II?

The problem primarily uses the two pointers technique on a string. No additional data structures such as hash maps or stacks are required because the palindrome property can be verified by comparing characters from both ends.

What is the time complexity of Valid Palindrome II?

The optimal solution runs in O(n) time where n is the length of the string. Each character is compared at most once during the two-pointer scan, and a mismatch triggers at most one additional linear palindrome check. Space complexity is O(1) for the iterative approach.

Valid Palindrome II Python or Java solution approach?

Both Python and Java implementations typically follow the same two-pointer strategy. Maintain left and right indices, compare characters, and on mismatch call a helper function that checks if the remaining substring is a palindrome. The logic remains O(n) time and O(1) space.

Is Valid Palindrome II asked at Google, Amazon, or Meta?

Valid Palindrome II appears frequently in coding interviews because it tests the two pointers pattern and edge case handling. Similar string symmetry problems have been reported in interviews at companies like Amazon, Google, and Meta.

Comments

Now write it yourselfClose this page and solve Valid Palindrome II in the editor, without looking.
Practise Valid Palindrome II