【力扣】1332.删除回文子序列|每日一题|刷题打卡

68 阅读2分钟

一、题目描述

给你一个字符串 s,它仅由字母 'a' 和 'b' 组成。每一次删除操作都可以从 s 中删除一个回文 子序列

返回删除给定字符串中所有字符(字符串为空)的最小删除次数。

「子序列」定义:如果一个字符串可以通过删除原字符串某些字符而不改变原字符顺序得到,那么这个字符串就是原字符串的一个子序列。

「回文」定义:如果一个字符串向后和向前读是一致的,那么这个字符串就是一个回文。

 

示例 1:

输入: s = "ababa"
输出: 1
解释: 字符串本身就是回文序列,只需要删除一次。

示例 2:

输入: s = "abb"
输出: 2
解释: "abb" -> "bb" -> "". 
先删除回文子序列 "a",然后再删除 "bb"

示例 3:

输入: s = "baabb"
输出: 2
解释: "baabb" -> "b" -> "". 
先删除回文子序列 "baab",然后再删除 "b"

 

提示:

  • 1 <= s.length <= 1000
  • s 仅包含字母 'a'  和 'b'

二、思路分析

  1. 一开始的思路是,根据题意得,首先判断字符串的长度,如果是空串,则返回0,如果是回文字符串,则返回1
  2. 接下来呢,就是判断不是回文字符串后,删除某一个字符后,可以组成的最大回文字符串,也就是 step,然后在将剩余的字符串递归,count累加的次数就是删除的次数

可是,在测试到bbaabaaa这个的时候,如果用下面这个方法,就执行不通啦,它执行的过程是

  • 从字符bbaabaaa中得到的最大回文字符的长度为aabaa,所以 step4index2,剩下字符为bba
  • bba -> 删除 a -> bb
  • 最后在删除bb,所以一共三次

但是最终运行后发现是错误,期望是2次,怎么也没想明白为什么是2次,后来才发现原来如果不是回文串,只要取所有的b或a,然后在删除剩下的a或b,则一共2次,就是最小的删除次数了

var removePalindromeSub = function (s) {
  let count = 0
  var work = function (s) {
    if (s.length === 0) return count
    if (isPalindrome(s)) return ++count
    let step = 0
    let index = 0
    for (var i = 0; i < s.length; i++) {
      for (var j = i; j < s.length; j++) {
        let str = s.substring(i, j + 1)
        if (isPalindrome(str)) {
          // 如果是回文串,就保存起来 
          if (j - i > step) {
            step = j - i
            index = i
          }
        }
      }
    }
    count++
    let arr = s.split("")
    arr.splice(index, step + 1)
    work(arr.join(""))
  }
  work(s)
  return count
};

三、代码答案

最终答案:只要不是回文串,那么其他情况都是2次

/**
 * @param {string} s
 * @return {number}
 */
var removePalindromeSub = function (s) {
  if (s.length === 0) return 0
  if (isPalindrome(s)) return 1
  return 2
};

function isPalindrome(s) {
  let left = 0, right = s.length - 1;
  while (left < right) {
    if (s[left] !== s[right]) {
      return false;
    }
    left++;
    right--;
  }
  return true;
}