leetcode 5# 最长回文子串的三种解法

113 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

最长回文子串

题目

5. 最长回文子串

难度中等5779收藏分享切换为英文接收动态反馈

给你一个字符串 s,找到 s 中最长的回文子串。

 

示例 1:

输入: s = "babad"
输出: "bab"
解释: "aba" 同样是符合题意的答案。

示例 2:

输入: s = "cbbd"
输出: "bb"

暴力解法

最简单就是暴力解法,即双重循环遍历,依次判断左右元素所组成的字串是否为回文串。

function longestPalindrome(s: string): string {
  if (s.length < 2) {
    return s;
  }
  let maxLen = 1;
  // maxLength最小为1
  let begin = 0;
  for (let i = 0; i < s.length - 1; i++) {
    for (let j = i + 1; j < s.length; j++) {
    //当左右相等进行判断
      if (s[i] === s[j]) {
        // 此时需要length>1,也就是j-i+1,最小为2.
        if (j - i + 1 > maxLen && compare(i, j, s)) {
        //当新的回文串长度更长时改变
          maxLen = j - i + 1;
          //maxLen 应该是左右边界数学相减后加一,slice能够得到正确的结果
          begin = i;
          //左边界转为起始位置
        }
      }
    }
  }
  console.log(begin, maxLen + 1);

  return s.slice(begin, begin + maxLen);
}

const compare = (i: number, j: number, s: string): boolean => {
  while (j - i >= 2) {
    if (s[i] === s[j]) {
      i++;
      j--;
    } else {
      return false;
    }
  }
  if (s[i] === s[j]) {
    return true;
  } else return false;
};
const v = longestPalindrome("aacabdkacaa");
console.log(v);

中心扩散法

明显暴力解法是很慢的,做过一些题的小伙伴一定是最先想到中心扩散这种解法,它更快是因为它只需要遍历中心坐标。

我们对每一个中心下标进行判断寻找,找到以它为中心的最长的回文串,然后进行比较赋值。需要注意的是有偶数回文串的情况,也就是当s[i]===s[i+1]时我们是以s[i]和[s+1]为中心来寻找的。我们可以将s[i]中心元素作为两个元素来保证一个函数寻找到最长回文串。

function longestPalindrome(s: string): string {
  if (s.length < 2) {
    return s;
  }
  let maxLen = 1;
  let begin = 0;
  for (let i = 0; i < s.length - 1; i++) {
    let re = compare(s, i, i);
    if (re[1] - re[0] + 1 > maxLen) {
      begin = re[0];
      maxLen = re[1] - re[0] + 1;
    }
    //当两个相等时传入i,i+1;
    if (s[i] === s[i + 1]) {
      let res = compare(s, i, i + 1);
      if (maxLen < res[1] - res[0] + 1) {
        maxLen = res[1] - res[0] + 1;
        //maxLen依旧用相减加一获取
        begin = res[0];
      }
    }
  }
  console.log(begin, maxLen);

  return s.slice(begin, begin + maxLen);
}

//传入左右元素,若单元素为中心就传入left和right都为这个单元素。
const compare = (s: string, left: number, right: number): number[] => {
  while (left - 1 > -1 && right + 1 < s.length) {
    if (s[left - 1] == s[right + 1]) {
      left--;
      right++;
    } else {
      break;
    }
  }
  // 返回最后一个相等的左右边界
  return [left, right];
};

const v = longestPalindrome("ccc");
console.log(v);

空间换时间的动态规划

思想就是对于每个左右边界组成的回文字串,若左右边界相等那么它是否为回文字串取决与它的left++与right--组成的字串是否为回文字串,依次娃,而长度小于等于三的字串我们是能够很轻易的判断它是ture或false,设置s[i][i]为true。

// 动态规划
function longestPalindrome(s: string): string {
  if (s.length < 2) {
    return s;
  }

  let maxLen: number = 1;
  let begin = 0;

  let twoM: Array<Array<boolean>> = new Array<Array<boolean>>(s.length);
  // 创建s.length个长度的数组
  for (let i = 0; i < s.length; i++) {
    twoM[i] = new Array(s.length);
    twoM[i][i] = true;
    // 设置对角线为true
  }
  for (let right = 1; right < s.length; right++) {
    for (let left = 0; left < right; left++) {
      if (s[left] !== s[right]) {
        // 当不等直接判false
        twoM[left][right] = false;
      } else {
        if (right - left < 3) {
          // 当距离为小于等于二也就是两个相同或是三个相同也判true
          twoM[left][right] = true;
        } else {
          /*
            这是一个注意点,此时我们判它为内部接近的字串的真值
          */
          twoM[left][right] = twoM[left + 1][right - 1];
        }
      }

      if (twoM[left][right] && right - left + 1 > maxLen) {
        maxLen = right - left + 1;
        begin = left;
      }
    }
  }
  console.table(twoM);
  return s.slice(begin, begin + maxLen);
}
console.log(longestPalindrome("aaabbbb"));

总结

本次文章的难点在于学习动态规划的解法与思想,即用空间减少判断的次数。

结语

本次的文章到这里就结束啦!♥♥♥读者大大们认为写的不错的话点个赞再走哦 ♥♥♥

每天一个知识点,每天都在进步!♥♥