680. 验证回文串 II - 题解与分析
题目描述
给定一个字符串 s
,最多可以从中删除一个字符。请判断 s
是否能通过删除一个字符后变成回文字符串。如果能,则返回 true
;否则,返回 false
。
示例 1:
输入:s = "aba"
输出:true
示例 2:
输入:s = "abca"
输出:true
解释:你可以删除字符 'c'
。
示例 3:
输入:s = "abc"
输出:false
提示:
1 <= s.length <= 10^5
s
由小写英文字母组成
解题思路
回文字符串的定义
回文字符串是一个正读和反读都相同的字符串。比如 "aba"
和 "madam"
都是回文字符串。
本题关键点
- 最多删除一个字符:我们只允许最多删除一个字符,若删除一个字符后的字符串能变成回文字符串,返回
True
,否则返回False
。 - 双指针法:我们可以使用双指针从字符串的两端向中间靠拢。如果两指针指向的字符相等,继续向中间推进;如果字符不相等,我们有两种选择:
- 删除左侧的字符,判断删除后剩下的子串是否是回文。
- 删除右侧的字符,判断删除后剩下的子串是否是回文。
如果其中任何一种情况能形成回文字符串,返回 True
,否则返回 False
。
解决方案
我们可以通过以下步骤来实现解法:
- 使用双指针
left
和right
从字符串两端开始扫描。 - 如果
s[left] == s[right]
,则继续向中间推进。 - 如果
s[left] != s[right]
,我们有两种选择:- 删除
s[left]
,检查子串s[left+1:right+1]
是否是回文。 - 删除
s[right]
,检查子串s[left:right]
是否是回文。
- 删除
- 如果这两种选择中有一种能够形成回文字符串,则返回
True
。否则返回False
。
辅助函数:判断回文
我们定义一个辅助函数 is_palindrome
来判断给定子串是否是回文。
def is_palindrome(s: str, left: int, right: int) -> bool:while left < right:if s[left] != s[right]:return Falseleft += 1right -= 1return True
代码实现
class Solution:def validPalindrome(self, s: str) -> bool:# 双指针left, right = 0, len(s) - 1while left < right:if s[left] != s[right]:# 如果字符不匹配,尝试删除一个字符# 递归检查删除左侧字符后的子串或删除右侧字符后的子串是否是回文return is_palindrome(s, left + 1, right) or is_palindrome(s, left, right - 1)left += 1right -= 1return Truedef is_palindrome(s: str, left: int, right: int) -> bool:while left < right:if s[left] != s[right]:return Falseleft += 1right -= 1return True
时间复杂度
- 主函数
validPalindrome
:我们使用双指针从两端向中间遍历字符串。最坏情况下,我们会遍历整个字符串一次,时间复杂度为O(n)
,其中n
是字符串的长度。 - 辅助函数
is_palindrome
:每次递归调用时,我们最多需要遍历剩余的子串,时间复杂度为O(n)
。
因此,整体的时间复杂度为 O(n)
,其中 n
是字符串的长度。
空间复杂度
- 我们没有使用额外的空间,除了
left
和right
两个指针,空间复杂度是O(1)
。
代码示例
class Solution:def validPalindrome(self, s: str) -> bool:left, right = 0, len(s) - 1while left < right:if s[left] != s[right]:return is_palindrome(s, left + 1, right) or is_palindrome(s, left, right - 1)left += 1right -= 1return Truedef is_palindrome(s: str, left: int, right: int) -> bool:while left < right:if s[left] != s[right]:return Falseleft += 1right -= 1return True
总结
本题利用双指针从两端向中间扫描的方法,结合辅助函数判断子串是否是回文,解决了最多删除一个字符是否能使字符串成为回文的问题。通过优化判断回文的方式,时间复杂度保持在 O(n)
,效率较高,适合处理较长的字符串。