查看原文
其他

005. 最长回文子串 | Leetcode题解

Mark 画漫画的程序员 2022-06-23

点击上方“蓝色字体”,选择“设为星标

每天复习一道面试题,轻松拿大厂Offer~


题目描述

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设  s 的最大长度为 1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"

难度:

  • 难度:中等
  • 支持语言:JavaScriptJavaPython

相关标签

  • 回文
  • 动态规划
  • 字符串

相关企业

  • 阿里
  • 百度
  • 腾讯

思路

这是一道最长回文的题目,要我们求出给定字符串的最大回文子串。

5.longest-palindromic-substring

解决这类问题的核心思想就是两个字“延伸”,具体来说如果在一个不是回文字符串的字符串两端添加任何字符,或者在回文串左右分别加不同的字符,得到的一定不是回文串

5.longest-palindromic-substring-2

base case 就是一个字符(轴对称点是本身),或者两个字符(轴对称点是介于两者之间的虚拟点)。

5.longest-palindromic-substring-3

事实上,上面的分析已经建立了大问题和小问题之间的关联,基于此,我们可以建立动态规划模型。

我们可以用 dp[i][j] 表示 s 中从 i 到 j(包括 i 和 j)是否可以形成回文, 状态转移方程只是将上面的描述转化为代码即可:

if (s[i] === s[j] && dp[i + 1][j - 1]) {
  dp[i][j] = true;
}
  • 暴力匹配 (Brute Force)

  • 根据回文子串的定义,枚举所有长度大于等于 22 的子串,依次判断它们是否是回文;

  • 在具体实现时,可以只针对大于“当前得到的最长回文子串长度”的子串进行“回文验证”;

  • 在记录最长回文子串的时候,可以只记录“当前子串的起始位置”和“子串长度”,不必做截取。这一步我们放在后面的方法中实现。

关键点

  • ”延伸“(extend)

复杂度分析

  • 时间复杂度:
  • 空间复杂度:

代码

JavaScript 实现

/**
 * @来源:Javascript中文网 - 前端进阶资源教程 https://www.javascriptc.com/
 * @介绍:前端中文网是以前端进阶资源教程分享为主的专业网站,包括:前端、大厂面试题、typescript教程、程序人生、React.js
 * @lc app=leetcode id=5 lang=javascript
 *
 * [5] Longest Palindromic Substring
 */

/**
 * @param {string} s
 * @return {string}
 */

var longestPalindrome = function (s) {
  // babad
  // tag : dp
  if (!s || s.length === 0return "";
  let res = s[0];

  const dp = [];

  // 倒着遍历简化操作, 这么做的原因是dp[i][..]依赖于dp[i + 1][..]
  for (let i = s.length - 1; i >= 0; i--) {
    dp[i] = [];
    for (let j = i; j < s.length; j++) {
      if (j - i === 0) dp[i][j] = true;
      // specail case 1
      else if (j - i === 1 && s[i] === s[j]) dp[i][j] = true;
      // specail case 2
      else if (s[i] === s[j] && dp[i + 1][j - 1]) {
        // state transition
        dp[i][j] = true;
      }

      if (dp[i][j] && j - i + 1 > res.length) {
        // update res
        res = s.slice(i, j + 1);
      }
    }
  }

  return res;
};
/**
*  @作者:salter
*  @链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-chuan-by-fanzhanxiang/
*/

var longestPalindrome = function(s) {
   let ans = '';
    let n = s.length;
    let dp = Array.from(new Array(n), () => new Array().fill(0));
    for(let i = n-1; i >=0; i--) {
        for(let j = i; j < n; j++) {
            dp[i][j] = s[i] === s[j] && ( j - i < 2 || dp[i+1][j-1])
            if(dp[i][j] && j - i + 1 > ans.length) {
                ans = s.substr(i,j - i + 1);
            }
        }
    }
    return ans;
}

/**
*  @作者:liuxukang
*  @链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zui-pu-tong-de-dong-tai-gui-hua-by-liuxukang/
*/

var longestPalindrome = function (s) {
    if(!s && s < 2return s
    let len = s.length;
    let start = 0
    let end = 0;
    const calcPalindrome = (left,right) => {
        while(left >=0 && right < len && s[left] === s[right]){
            left--;
            right++;
        }

        return right -left -1
    }

    for(let i = 0; i < len; i++) {
        let s1 = calcPalindrome(i,i)
        let s2 = calcPalindrome(i,i+1)
        let maxLen = Math.max(s1,s2)
        if(maxLen > end -start ) {
            start = i - Math.floor((maxLen - 1) / 2)
            end = i + Math.floor(maxLen /2)
        }
    }
    return s.slice(start,end+1)
}


Java 实现

/**
*  @作者:windliang
*  @链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-bao-gu/
*/

public boolean isPalindromic(String s) {
  int len = s.length();
  for (int i = 0; i < len / 2; i++) {
   if (s.charAt(i) != s.charAt(len - i - 1)) {
    return false;
   }
  }
  return true;
 }

// 暴力解法
public String longestPalindrome(String s) {
    String ans = "";
    int max = 0;
    int len = s.length();
    for (int i = 0; i < len; i++)
        for (int j = i + 1; j <= len; j++) {
            String test = s.substring(i, j);
            if (isPalindromic(test) && test.length() > max) {
                ans = s.substring(i, j);
                max = Math.max(max, ans.length());
            }
        }
    return ans;
}

/**
*  @作者:liweiwei1419
*  @链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zhong-xin-kuo-san-dong-tai-gui-hua-by-liweiwei1419/
*/

public class Solution {

    public String longestPalindrome(String s) {
        int len = s.length();
        if (len < 2) {
            return s;
        }

        int maxLen = 1;
        int begin = 0;
        // s.charAt(i) 每次都会检查数组下标越界,因此先转换成字符数组
        char[] charArray = s.toCharArray();

        // 枚举所有长度大于 1 的子串 charArray[i..j]
        for (int i = 0; i < len - 1; i++) {
            for (int j = i + 1; j < len; j++) {
                if (j - i + 1 > maxLen && validPalindromic(charArray, i, j)) {
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        return s.substring(begin, begin + maxLen);
    }

    /**
     * 验证子串 s[left..right] 是否为回文串
     */

    private boolean validPalindromic(char[] charArray, int left, int right) {
        while (left < right) {
            if (charArray[left] != charArray[right]) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

Python 实现

class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        if n == 0:
            return ""
        res = s[0]
        def extend(i, j, s):
            while(i >= 0 and j < len(s) and s[i] == s[j]):
                i -= 1
                j += 1
            return s[i + 1:j]

        for i in range(n - 1):
            e1 = extend(i, i, s)
            e2 = extend(i, i + 1, s)
            if max(len(e1), len(e2)) > len(res):
                res = e1 if len(e1) > len(e2) else e2
        return res
# @作者:skay2002
# @链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/pythonshuang-bai-50msyi-lun-bian-li-fa-5-zui-chang/

class Solution:
    def longestPalindrome(self, s: str) -> str:
        if not s: return ""
        length = len(s)
        if length == 1 or s == s[::-1]: return s
        max_len,start = 1,0
        for i in range(1, length):
            even = s[i-max_len:i+1]
            odd = s[i-max_len-1:i+1]
            if i - max_len - 1 >= 0 and odd == odd[::-1]:
                start = i - max_len - 1
                max_len += 2
                continue
            if i - max_len >= 0 and even == even[::-1]:
                start = i - max_len
                max_len += 1
                continue
        return s[start:start + max_len]

# @作者:LeetCode-Solution
# @链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/

class Solution {
    public String longestPalindrome(String s) {
        int n = s.length();
        boolean[][] dp = new boolean[n][n];
        String ans = "";
        for (int l = 0; l < n; ++l) {
            for (int i = 0; i + l < n; ++i) {
                int j = i + l;
                if (l == 0) {
                    dp[i][j] = true;
                } else if (l == 1) {
                    dp[i][j] = (s.charAt(i) == s.charAt(j));
                } else {
                    dp[i][j] = (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]);
                }
                if (dp[i][j] && l + 1 > ans.length()) {
                    ans = s.substring(i, i + l + 1);
                }
            }
        }
        return ans;
    }
}

相关题目

  • 516.longest-palindromic-subsequence
  • https://www.javascriptc.com/special/leetcode

其他

  • 原题leetcode链接:https://leetcode-cn.com/problems/longest-palindromic-substring/
  • 合作方:JavaScript中文网 – 全球极客挚爱的技术成长平台
  • 说明:leetcode 题解 | 每日一题🔥 所有题目并非全部为本人解答,部分为在复习学习中整理提取其他解题作者的优秀笔记,便于大家学习共同进步,如有侵权,请联系删除。
完 -
关注公众号「IT平头哥联盟」,一起进步,一起成长!

004. 寻找两个正序数组的中位数 | Leetcode题解

003. 无重复字符的最长子串 | Leetcode题解

002. 两数相加 | Leetcode题解

001. 两数之和 | Leetcode题解

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存