LeetCode 680简单双指针
验证回文串 II 图解题解
这道题到底在问什么
给你一个字符串 s,最多可以从中删除一个字符。请你判断 s 是否能成为回文字符串:如果能,返回 true;否则,返回 false。
- 输入
- s = "aba"
- 输出
- true
- 输入
- s = "abca"
- 输出
- true
- 解释
- 可以删除字符 'c',得到 "aba"。
- 输入
- s = "abc"
- 输出
- false
最优解:一步一步想明白
- 3我们只需要在第一次左右字符不等时分叉一次,因为前面已经匹配过,后面也只剩两个可能的删除位置。
- 4helper check 是严格回文检查:进入 check 之后不能再删第二个字符。
- 5l = 0; r = len(s) - 1主流程先用左右指针检查完整字符串 abca。
- 6if s[l] != s[r]: 不成立两端相等,说明这两个字符不用删除,可以放心往中间收缩。
- 7l += 1; r -= 1外层已经确认的 a/a 不会再影响答案,真正的问题落在中间的 b/c。
- 8if s[l] != s[r]:这是第一次不匹配。因为最多只能删一个字符,所以现在只剩两条路:跳过 b,或者跳过 c。
- 9check(l + 1, r)外层原始指针记录为 outerL=1、outerR=2;候选一把 helper 的检查区间改成 checkL=2、checkR=2,相当于跳过左字符 b。单个字符天然是回文。
- 10check 返回 True注意 check 里没有再次删除的机会;此时 l==r,while l < r 不进入,直接返回 True。
- 11check(l, r - 1)外层原始指针记录为 outerL=1、outerR=2;候选二把 helper 的检查区间改成 checkL=1、checkR=1,相当于跳过右字符 c。
- 12check 返回 Trueabca 这一例里,删 b 或删 c 都能成功。此时 l==r,check 直接返回 True;代码用 or,任意一个候选为 true 就能返回 true。
- 13return check(l + 1, r) or check(l, r - 1)第一次不匹配时已经用掉删除机会,返回两个严格回文检查结果的 or。
- 14如果两个候选区间都不是普通回文,就说明删一个字符也救不了。
- 17这也是双指针题里常见的贪心边界:前面相等的字符没必要回头改。
⚠️ 容易写错的地方
✗ 错:第一次不等直接 false
✓ 对:尝试 check(l+1,r) 或 check(l,r-1)
题目允许最多删除一个字符。
✗ 错:在 check 里继续允许删除
✓ 对:check 只做普通回文判断
删除机会只能用一次,不能层层递归删。
✗ 错:枚举每个删除位置并构造新串
✓ 对:只在第一次不匹配处分叉
长度到 10^5 时,构造新串会浪费时间和空间。
完整代码(Python)
Python
class Solution:
def validPalindrome(self, s):
def check(l, r):
while l < r:
if s[l] != s[r]:
return False
l += 1
r -= 1
return True
l = 0
r = len(s) - 1
while l < r:
if s[l] != s[r]:
return check(l + 1, r) or check(l, r - 1)
l += 1
r -= 1
return True复杂度
时间复杂度
O(n)
外层最多扫一遍;第一次不匹配时最多再检查两个不重叠候选区间的线性长度。
空间复杂度
O(1)
只使用左右指针,没有构造新字符串。
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 验证回文串 II 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
这道题为什么用「双指针」,换最直接的暴力解会差在哪?+
双指针抓住了本题的结构特征,把暴力解里重复的工作省掉;暴力解通常要多嵌套一层枚举,数据一大就超时。具体对比见上文「暴力解及其卡点」与「最优解逐步推演」两节。
时间复杂度为什么是 undefined?怎么推出来的?+
按上文复杂度小节的推导,时间复杂度为 undefined。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。