【LeetCode】5. 最长回文子串

5. 最长回文子串

知识点:动态规划;回文串

题目描述

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

示例
输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。 输入:s = "cbbd" 输出:"bb" 输入:s = "a" 输出:"a" 输入:s = "ac" 输出:"a"

解法一:暴力法

从头开始找最长回文子串;记录最长串的开始位置和长度,最后从s中截取就可以了;

class Solution { public String longestPalindrome(String s) { int len = s.length(); if(len < 2) return s; int maxLen = 1; int begin = 0; //得到起始位置和长度就能得到了; char[] ch = s.toCharArray(); for(int i = 0; i < len-1; i++){ for(int j = i+1; j < len; j++){ //最长回文子串:是回文串,而且大于之前的长度; if(j-i+1 > maxLen && isHuiWen(ch, i, j)){ maxLen = j-i+1; begin = i; } } } return s.substring(begin, begin+maxLen); } private boolean isHuiWen(char[] ch, int start, int end){ while(start < end){ if(ch[start] == ch[end]){ start++; end--; }else{ return false; } } return true; } }

解法二:动态规划;

此题可以用动态规划去做,因为回文串天然具有状态转移的性质,比如一个子串如果是回文子串,那把前后两个字符去掉后依然是回文子串。那反过来,就可以根据前面的子串来判断新的子串了。

  • 1.确定dp数组和其下标的含义;dp[i][j]表示子串s[i:j]是否是回文子串;
  • 2.确定递推公式,即状态转移方程;先填写j,因为i必须在j前面,i<j;判断首尾字符,如果不相等直接false,如果相等,那就状态转移,dp[i][j] = dp[i+1][j-1];
  • 3.dp初始化;base case; 长度为1的,也就是dp[i][i]=true;
class Solution { public String longestPalindrome(String s) { int maxLen = 1; int begin = 0; int len = s.length(); boolean[][] dp = new boolean[len][len]; //s[i:j]是否是回文串; for(int i = 0; i < len; i++){ dp[i][i] = true; //长度为1肯定都是; } char[] ch = s.toCharArray(); for(int j = 1; j < len; j++){ for(int i = 0; i < j; i++){ //头尾不等,肯定不是; if(ch[i] != ch[j]){ dp[i][j] = false; }else{ //两者中间没有元素或者有一个元素,true; if(j-i <= 2){ dp[i][j] = true; }else{ dp[i][j] = dp[i+1][j-1]; //状态转移; } } if(dp[i][j] && j-i+1 > maxLen){ maxLen = j-i+1; begin = i; } } } return s.substring(begin,begin+maxLen); } }
  • python
class Solution: def findLongestHuiWenStr(self, s: str) -> str: if len(s) < 2: return s begin = 0 maxlen = 1 dp = [[False] * len(s) for _ in range(len(s))] for i in range(len(s)): dp[i][i] = True for j in range(1, len(s)): for i in range(j): if s[i] != s[j]: dp[i][j] = False else: if j-i <= 2: dp[i][j] = True else: dp[i][j] = dp[i+1][j-1] if dp[i][j] and j-i+1 > maxlen: maxlen = j-i+1 begin = i return s[begin:begin+maxlen]

解法三:中心扩散;

从头到尾去进行遍历,然后以该元素为中心值去扩散,比较扩散的两端的值是否相等,相等的话就接着扩散,不等的话就返回最大子串的长度。

注意细节就是奇数和偶数是不同的,比如aba以b扩散,和abba以bb进行扩散,所以扩散的时候左右两点分别是[i,i]和[i,i+1];

class Solution { public String longestPalindrome(String s) { int len = s.length(); int maxLen = 1; int begin = 0; for(int i = 0; i < len-1; i++){ int len1 = expandCenter(s, i, i); //偶数中心扩散; int len2 = expandCenter(s, i, i+1); //奇数中心扩散; len1 = Math.max(len1, len2); if(len1 > maxLen){ maxLen = len1; begin = i-(maxLen-1)/2; //奇数:i-maxLen/2; 偶数:i-maxLen/2+1; 将两者统一; } } return s.substring(begin, begin+maxLen); } private int expandCenter(String s, int left, int right){ while(left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)){ left--; right++; } return right-left-1; //最后两个是已经越界的。right-left+1-2; } }
def findLongestHuiWenStr(self, s: str) -> str: if len(s) < 2: return s begin = 0 maxlen = 0 len = 1 for i in range(len(s)): left = i-1 right = i+1 while left >= 0 and s[left] == s[i]: len += 1 left -= 1 while right < len(s) and s[right] == s[i]: len += 1 right += 1 while left >= 0 and right < len(s) and s[right] == s[left]: len += 2 left -= 1 right += 1 maxlen = max(maxlen, len) begin = left len = 1 return s[begin+1:begin+1+maxlen]

__EOF__

本文作者Curryxin
本文链接https://www.cnblogs.com/Curryxin/p/15139730.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Curryxin  阅读(107)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
Live2D
欢迎阅读『【LeetCode】5. 最长回文子串』
点击右上角即可分享
微信分享提示