每日刷题day15----最长回文子序列

107 阅读2分钟

image.png 首先大家要知道 回文数 就是正着读 和 反着读 一样的数字,区分大小写

思路1: 一般遇到极值问题,大多就是动态规划解题了

动态规划解题的关键是找到状态转移方程

我们用二维数组dp[i][j]来记录从i到j的子串是否满足回文数,那么一般就是三种情况

(1) i===j, 此时单个字符满足回文数

(2) j-i ===1 此时s[i]===s[j]才满足回文数

(3)其余情况,满足 dp[i][j]= s[i]===s[j] && dp[i+1][j-1]

这里需要注意的是数组的遍历顺序,因为dp[i][j]依赖dp[i+1][j-1],也就是依赖当前左下角的值来做判断,且在对角线位置的值一定为1,因此我们只需要遍历右上半部分。从下向上,从左到右遍历数组

/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function(s) {
  let res = ''
  let len = s.length
  let dp = new Array(len).fill(0).map(x=>new Array(len).fill(0))
  console.log(dp)
  for(let i=len-1;i>=0;i--){
      for(let j = i;j<len;j++){
          if(i === j){
              dp[i][j] = 1
          }else if(j - i === 1){
              if(s[i] === s[j]){
                  dp[i][j] = 1
              }
          }else{
              dp[i][j] = ( s[i] === s[j] && dp[i+1][j-1] )
          }

          if(dp[i][j] && j-i +1 > res.length){
              res = s.substring(i,j+1)
          }
      }
  }
 return res
  

};

思路2: 双指针

所谓回文就是指以某个字符为中心,不断向左右两边扩充相同字符,这样形成的字符串一定是回文。

那么我们只要遍历每一个字符,找出以这个字符为中心,向两边能扩散出的最长字符串并比较即可。

注意这里回文串可能有两种情况:回文串为奇数时,中心字符为1个。回文串为偶数时,中心字符为相等的两个字符,需要分别来运算

/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function(s) {
let res = ''
const len = s.length
for(let i=0;i<len;i++){
    const subStr1 = longSub(i,i)
    const subStr2 = longSub(i,i+1)
    const temp = subStr1.length > subStr2.length?subStr1:subStr2
    res = res.length>temp.length ?res:temp

}
return res

function longSub(left,right){
    while(left>=0 && right <= s.length && s[left] == s[right]){
        left--;
        right++
    }
    return s.substring(left+1,right)
}

};