题目描述
给你一个字符串 s,找到 s 中最长的回文子串。
算法思路
动态规划:
讨论:
所有的单个字母是回文子串。
字母个数从2开始,使用dp。当数组的第i个数值和第j个字母相同,二维数组dp记录为true。接着判断当前子串的子串外层,即第i+1个位置和第j-1个位置的字母是否相同,以此递归。同时更新所得子串最大长度。
中心扩散法:
设置左右指针,遍历每一个字母。
讨论:如果左指针指向的字母和当前i位置的字母相同就左移,长度加一,继续左移。
右侧同样。
左指针指向的字母和右指针指向的字母相同,长度加二,同时进行左移和右移。
示例代码
动态规划:
class Solution {
public String longestPalindrome(String s) {
int len = s.length();
//特殊处理
if (len < 2) {
return s;
}
boolean[][] dp = new boolean[len][len];
int begin = 0;//左边界
int maxLen = 1;//符合要求子串长度
for (int i = 0; i < len; i++) {
dp[i][i] = true;
}
char[] charArray = s.toCharArray();
//分情况讨论子串长度
for (int L = 2; L <= len; L++) {
for (int i = 0; i < len; i++) {
int j = L + i - 1;
//右边界出界
if (j >= len) {
break;
}
//对当下子串的子串进行判断
if (charArray[i] != charArray[j]) {
dp[i][j] = false;
} else {
if (j - i < 3) {
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);
}
}
时间复杂度:O(n²),n是字符串长度。动态规划的状态总数为O(n²),每个状态转移的时间为 O(1)。
空间复杂度:O(n²),存储每个状态所需要的总空间。
中心扩散法:
public String longestPalindrome(String s) {
if (s == null || s.length() == 0) {
return "";
}
int strLen = s.length();
int left = 0;
int right = 0;
int len = 1;
int maxStart = 0;
int maxLen = 0;
for (int i = 0; i < strLen; i++) {
left = i - 1;
right = i + 1;
while (left >= 0 && s.charAt(left) == s.charAt(i)) {
len++;
left--;
}
while (right < strLen && s.charAt(right) == s.charAt(i)) {
len++;
right++;
}
while (left >= 0 && right < strLen && s.charAt(right) == s.charAt(left)) {
len = len + 2;
left--;
right++;
}
if (len > maxLen) {
maxLen = len;
maxStart = left;
}
len = 1;
}
return s.substring(maxStart + 1, maxStart + maxLen + 1);
}
时间复杂度:O(n²)。
空间复杂度:O(1)。
本文详细解析了如何通过动态规划和中心扩散法寻找字符串中的最长回文子串。动态规划通过二维数组记录字符相似性,中心扩散则利用左右指针遍历并扩展回文区。两种方法的时间复杂度均为O(n²),但空间复杂度不同:动态规划为O(n²),中心扩散法为O(1)。
405

被折叠的 条评论
为什么被折叠?



