Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using core interview patterns strategy.
You are given a string s consisting of lowercase English letters.
A substring is almost-palindromic if it becomes a palindrome after removing exactly one character from it.
Return an integer denoting the length of the longest almost-palindromic substring in s.
Example 1:
Input: s = "abca"
Output: 4
Explanation:
Choose the substring "abca".
"abca"."aba", which is a palindrome."abca" is almost-palindromic.Example 2:
Input: s = "abba"
Output: 4
Explanation:
Choose the substring "abba".
"abba"."aba", which is a palindrome."abba" is almost-palindromic.Example 3:
Input: s = "zzabba"
Output: 5
Explanation:
Choose the substring "zzabba".
"zabba"."abba", which is a palindrome."zabba" is almost-palindromic.Constraints:
2 <= s.length <= 2500s consists of only lowercase English letters.Problem summary: You are given a string s consisting of lowercase English letters. A substring is almost-palindromic if it becomes a palindrome after removing exactly one character from it. Return an integer denoting the length of the longest almost-palindromic substring in s.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: General problem-solving
"abca"
"abba"
"zzabba"
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #3844: Longest Almost-Palindromic Substring
class Solution {
private int n;
private char[] s;
public int almostPalindromic(String s) {
n = s.length();
this.s = s.toCharArray();
int ans = 0;
for (int i = 0; i < n; i++) {
ans = Math.max(ans, f(i, i));
ans = Math.max(ans, f(i, i + 1));
}
return ans;
}
private int f(int l, int r) {
while (l >= 0 && r < n && s[l] == s[r]) {
l--;
r++;
}
int l1 = l - 1, r1 = r;
int l2 = l, r2 = r + 1;
while (l1 >= 0 && r1 < n && s[l1] == s[r1]) {
l1--;
r1++;
}
while (l2 >= 0 && r2 < n && s[l2] == s[r2]) {
l2--;
r2++;
}
return Math.min(n, Math.max(r1 - l1 - 1, r2 - l2 - 1));
}
}
// Accepted solution for LeetCode #3844: Longest Almost-Palindromic Substring
func almostPalindromic(s string) int {
n := len(s)
f := func(l, r int) int {
for l >= 0 && r < n && s[l] == s[r] {
l--
r++
}
l1, r1 := l-1, r
l2, r2 := l, r+1
for l1 >= 0 && r1 < n && s[l1] == s[r1] {
l1--
r1++
}
for l2 >= 0 && r2 < n && s[l2] == s[r2] {
l2--
r2++
}
return min(n, max(r1-l1-1, r2-l2-1))
}
ans := 0
for i := 0; i < n; i++ {
ans = max(ans, f(i, i), f(i, i+1))
}
return ans
}
# Accepted solution for LeetCode #3844: Longest Almost-Palindromic Substring
class Solution:
def almostPalindromic(self, s: str) -> int:
def f(l: int, r: int) -> int:
while l >= 0 and r < n and s[l] == s[r]:
l -= 1
r += 1
l1, r1 = l - 1, r
l2, r2 = l, r + 1
while l1 >= 0 and r1 < n and s[l1] == s[r1]:
l1 -= 1
r1 += 1
while l2 >= 0 and r2 < n and s[l2] == s[r2]:
l2 -= 1
r2 += 1
return min(n, max(r1 - l1 - 1, r2 - l2 - 1))
n = len(s)
ans = 0
for i in range(n):
a = f(i, i)
b = f(i, i + 1)
ans = max(ans, a, b)
return ans
// Accepted solution for LeetCode #3844: Longest Almost-Palindromic Substring
// Rust example auto-generated from java reference.
// Replace the signature and local types with the exact LeetCode harness for this problem.
impl Solution {
pub fn rust_example() {
// Port the logic from the reference block below.
}
}
// Reference (java):
// // Accepted solution for LeetCode #3844: Longest Almost-Palindromic Substring
// class Solution {
// private int n;
// private char[] s;
//
// public int almostPalindromic(String s) {
// n = s.length();
// this.s = s.toCharArray();
// int ans = 0;
// for (int i = 0; i < n; i++) {
// ans = Math.max(ans, f(i, i));
// ans = Math.max(ans, f(i, i + 1));
// }
// return ans;
// }
//
// private int f(int l, int r) {
// while (l >= 0 && r < n && s[l] == s[r]) {
// l--;
// r++;
// }
//
// int l1 = l - 1, r1 = r;
// int l2 = l, r2 = r + 1;
//
// while (l1 >= 0 && r1 < n && s[l1] == s[r1]) {
// l1--;
// r1++;
// }
// while (l2 >= 0 && r2 < n && s[l2] == s[r2]) {
// l2--;
// r2++;
// }
//
// return Math.min(n, Math.max(r1 - l1 - 1, r2 - l2 - 1));
// }
// }
// Accepted solution for LeetCode #3844: Longest Almost-Palindromic Substring
function almostPalindromic(s: string): number {
const n = s.length;
const f = (l: number, r: number): number => {
while (l >= 0 && r < n && s[l] === s[r]) {
l--;
r++;
}
let l1 = l - 1,
r1 = r;
let l2 = l,
r2 = r + 1;
while (l1 >= 0 && r1 < n && s[l1] === s[r1]) {
l1--;
r1++;
}
while (l2 >= 0 && r2 < n && s[l2] === s[r2]) {
l2--;
r2++;
}
return Math.min(n, Math.max(r1 - l1 - 1, r2 - l2 - 1));
};
let ans = 0;
for (let i = 0; i < n; i++) {
ans = Math.max(ans, f(i, i));
ans = Math.max(ans, f(i, i + 1));
}
return ans;
}
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.