LeetCode 680. 验证回文串 II
题目描述

题意分析
判断整个字符串能否在最多删除一个字符后成为回文,删除零个也允许。题目只包含小写英文字母,直接按下标比较字符即可,不需要过滤或转换大小写。
枚举每个删除位置再检查回文会重复扫描。回文要求两端字符依次对应,因此先用双指针从两端向内比较,把删除选择推迟到第一次不相等的位置,就只剩两个候选需要检查。
解法:双指针 + 一次跳过
核心思路
[!blue]
left、right表示尚未检查的闭区间,区间外的字符已经成对匹配,删除机会仍未使用。两端相等时,可以同时内缩而不删除。删除内部字符的可行方案显然仍被保留;对于长度至少为三的区间,若某个可行方案删除了端点,删后的回文要求该端点旁的内侧字符与它相同,改删这个相同的邻字符会得到同样的字符串。因此总能保留这对相等端点,把删除机会留给内部。长度不超过二且两端相等时,本身已经是回文。
第一次出现
s[left] != s[right]时,删除区间内部的字符无法改变这对失配端点,所以唯一可能是删除左端或删除右端,分别对应[left+1, right]和[left, right-1]。删除机会已用完,辅助函数只能检查剩余区间是否原样为回文,不能再次跳过字符。任一候选为回文,就能与外侧已经匹配的字符一起组成完整回文;两个候选都失败,则不存在合法删除。可以先检查删左的候选,成功就短路返回;失败后仍必须检查删右,不能只凭下一对字符是否相等决定删哪边。
解题步骤
- 左右指针从字符串两端开始;字符相等时同时向内移动。
- 第一次失配时立即返回两个候选的结果:跳过左字符,或跳过右字符。
- 辅助函数只判断指定闭区间是否为回文,不能再删除字符。
- 主循环没有失配就返回
true。
代码实现
class Solution {
public boolean validPalindrome(String s) {
int left = 0;
int right = s.length() - 1;
while (left < right) {
if (s.charAt(left) == s.charAt(right)) {
left++;
right--;
} else {
// 最多只能删除一个字符,所以只尝试两种跳过方式。
return isPalindrome(s, left + 1, right) || isPalindrome(s, left, right - 1);
}
}
return true;
}
private boolean isPalindrome(String s, int left, int right) {
while (left < right) {
if (s.charAt(left++) != s.charAt(right--)) {
return false;
}
}
return true;
}
}
func validPalindrome(s string) bool {
left := 0
right := len(s) - 1
for left < right {
if s[left] == s[right] {
left++
right--
} else {
// 删除左字符或右字符,任意一种可行即可。
return isPalindromeRange(s, left+1, right) || isPalindromeRange(s, left, right-1)
}
}
return true
}
func isPalindromeRange(s string, left int, right int) bool {
for left < right {
if s[left] != s[right] {
return false
}
left++
right--
}
return true
}
复杂度分析
- 时间复杂度:$O(n)$。主循环和两次候选区间检查都是线性扫描,分支只发生一次,总工作量仍是线性级别。
- 空间复杂度:$O(1)$。只有几个下标变量,全程在原字符串上按下标比较,没有构造任何子串或额外数组,辅助函数也是迭代写法,调用栈只有常数深度。
关键点总结
[!green]
- 两端相等时,保留这一对不会排除所有可行方案,所以删除选择可以推迟到首次失配。
- 唯一的分叉点是第一次失配处,此后删除机会已用尽,两支各自退化成纯回文判断,这正是复杂度停在 $O(n)$ 的原因。
- 辅助函数里绝不能再写跳过逻辑,它的职责就是「这段区间原样是不是回文」。
易错点总结
[!yellow]
- 只固定尝试删左或删右,会漏掉必须删除另一端的情况;第一条候选失败后还要检查另一条。
- 内侧一对字符相等不能决定整段是否可行,候选区间必须完整判回文。
- 辅助判断若再次允许删除,会错误接受需要多次删除的字符串。
- 同时跳过两端等于删除两个字符,不符合最多一次。
- 右指针从
length-1开始,不能从字符串长度开始读取。- 指针相遇或交错时,剩余区间长度至多为一,已经是回文;这也覆盖单字符输入,以及两个字符失配后删掉任一端的情况。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 125. 验证回文串 | 简单 | 原题只需按过滤规则验证回文,本题在首次失配处增加一次删除选择。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!