leetcode.680 验证回文字符串 Ⅱ | 刷题打卡

221 阅读3分钟

一、题目描述

给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。

示例 1:

输入: "aba" 输出: True

示例 2:

输入: "abca" 输出: True 解释: 你可以删除c字符。

注意: 字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。

二、思路分析

注意读题,非空字符串最多删除一个字符,判断是否能成为回文字符串。那应该存在两种情况,其自身就是回文字符串,或者去掉一位后是一个回文字符串。那第一步我们要解决的肯定是判断字符串是否回文。

1.判断字符串回文

这个问题有点眼熟,不就是前两天我写过的验证回文字符串 一的题解吗

在这里首先想到的应该是字符串反转与自身比较是否相等,因为js字符串不支持直接反转,所以需要将字符串转化为数组,反转后再转化为字符串与自身比较,直接上代码

const isPalindrome = str => str.split('').reverse().join('') === str

另一种方法当然是使用双指针,使用头尾两个指针比较字符串字符是否相等,相等则两个指针相向移动,直到两个指针相遇或相邻则停止。

const isPalindrome = str => Array
            .from({length: str.split('').length >> 1})
            .every((v, i) => str[i] === str[str.length - i - 1])

2.去除每一位字符验证

开始我的思路是循环字符串,将每一位字符从字符串移除后判断剩下的字符串是否为回文,直接上代码

var validPalindrome = function (s) {
  const isPalindrome = str => str.split('').reverse().join('') === str
  if (isPalindrome(s)) return true
  let sArr = s.split('')
  return Array.from({length: s.length}).some((v, i) =>
    isPalindrome(sArr.filter((v, inx) => inx !== i).join(''))
  )
};

时间复杂度O(n^2)果不其然超时了,继续优化。

3.去掉一位就能达到回文的条件

换一种思路可能会发现问题比预想的要更简单。先来想想我们用双指针是如何判断字符串回文的:两个指针位于字符串首尾字符,判断两个字符是否相等,如果相等那么两个指针相向移动,再次判断,直到指针相遇。

本题的最多删除一个字符后字符串是否回文,可以理解为判断字符串回文且有一次容错的机会,当遇到首位指针移动且不相等时,跳过这次判断继续执行(这里有删除左边指针和删除右边指针两种情况,这里直接校验左指针右移和右指针左移两种情况),如果再遇到不相等,之后的判断就和二分法判断字符是否相等完全一致了。

var validPalindrome = function (s) {
const isPalindrome = str => Array
            .from({length: str.split('').length >> 1})
            .every((v, i) => str[i] === str[str.length - i - 1])

  for (let i = 0; i < s.length >> 1; i++) {
    if (s[i] !== s[s.length - i - 1]) {
      if (s[i] === s[s.length - i - 2] || s[i + 1] === s[s.length - i - 1]) {
        return isPalindrome(s.split('').filter((v, index) => index >= i && index < (s.length - i - 1)).join(''))
          || isPalindrome(s.split('').filter((v, index) => index > i && index <= (s.length - i - 1)).join(''))
      } else {
        return false
      }
    }
  }
  return true
}

END


本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情