题目描述
给定一个字符串s,找到s中最长的回文子串。
难度:中等
题目链接:https://leetcode.cn/problems/longest-palindromic-substring/
示例1:
输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。
示例2:
输入:s = "cbbd" 输出:"bb"
提示:
- 1<=s.length<=1000
- s仅由数字和英文字母组成
解题思路
- 双指针法/中心拓展法
回文串是以中心对称的,可以从中心位置开始,向两边拓展,找到以该位置为中心的最长回文串。回文串的中心可以是一个字符(奇数)或者两个字符(偶数),最后记录最长的回文子串。
public class Solution { public string LongestPalinedrome(string s) { if(string.IsNullOrEmpty(s)) return ""; int start = 0,maxLength=0; for(int i=0;i<s.Length;i++) { //尝试奇数长度的回文串 int len1=ExpandAroundCenter(s,i,i); //尝试偶数长度的回文串 int len2=ExpandAroundCenter(s,i,i+1); //更新最长回文串的信息 int len = Math.Max(len1,len2); if(len>manLength) { maxLength = len; start = i-(len-1)/2; } } return s.Substring(start,maxLength); } private int ExpandAroundCenter(string s,int left,int right) { //从中心向两边拓展,直到不能形成回文 while(left>=0 && right<s.Length && s[left]==s[right]) { left--;right++; } //返回回文串的长度 return right-left-1; } }
- 动态规划
使用动态规划可以避免重复计算,定义dp[i][j]表示s[i....j]是否是回文串。状态转移方程如下:
dp[i][j]=(s[i]==s[j])&&(j-i<3 || dp[i+1][j-1])
public class Solution{ public string LongestPalinedrome(string s) { int n=s.Length; bool dp[n][n]; int maxLength=1,start=0; //所有单个字符都是回文 for(int i=0;i<n;i++) dp[i][i]=true; //长度为2的子串 for(int i=0;i<n-1;i++) { if(s[i]==s[i+1]) dp[i][i+1]=ture,start=i,maxLength=2; } //长度大于2的子串 for(int len=3;len<=n;len++) for(int i=0;i<=n-len;i++) { int j=i+len-1; if(s[i]==s[j] && dp[i+1][j-1]) { dp[i][j]=true; if(len>maxLength) start=i,maxLength=len; } } return s.Substring(start,maxLength); } }
中心拓展法相较于动态规划,其时间复杂度和空间复杂度都较低。