本文已参与「新人创作礼」活动,一起开启掘金创作之路。
题目来源:leetcode-cn.com/problems/lo…
大致题意: 给一个字符串,求出其最长的回文子串
思路
可以直接使用动态规划,使用一个 n*n 的二维数组 dp[i][j] 表示 i - j 的子串是否是回文串
动态规划
使用 dp[i][j] 表示 i-j 的子串是否为回文串,那么
- 若 i 位字符与 j 位字符不相等,显然不为回文串,dp[i][j] 为 false
- 若 i 位字符与 j 位字符相等,若此时子串长度小于等于 3,则子串一定为回文串;否则 dp[i][j] 的值即为 dp[i+1][j-1] 的值
算法过程为:
- 使用 n*n 的二维布尔数组 dp[i][j] 表示 i - j 的子串是否是回文串,并存下目前的最长回文子串,初始时,dp[i][i] 为 true
- 从长度 2 遍历到长度 n
- 每次遍历,都遍历当前长度的所有子串,判断是否为回文串。遍历过程中,更新最长回文串
具体看代码:
public String longestPalindrome(String s) {
int max = 1; // 最长回文子串的长度
int begin = 0; // 最长回文子串的起始位置
int n = s.length();
boolean[][] dp = new boolean[n][n];
// 初始化
for (int i = 0; i < n; i++) {
dp[i][i] = true;
}
// 遍历长度 2 至 n
for (int len = 2; len <= n; len++) {
// 遍历当前长度的所有子串
// i 可以视为子串左边界
for (int i = 0; i < n - len + 1; i++) {
// j 可以视为子串右边界
int j = i + len - 1;
// 若边界处字符不等,一定不为回文串,跳过
if (s.charAt(i) != s.charAt(j)) {
continue;
}
// 相等的情况
// 若子串长度小于等于 3,一定为回文串
if (j - i < 3) {
dp[i][j] = true;
} else { // 长度大于 3,是否是回文串与内部字符串相关
dp[i][j] = dp[i + 1][j - 1];
}
// 更新最长的回文串
if (dp[i][j] && len > max) {
max = len;
begin = i;
}
}
}
return s.substring(begin, max + begin);
}