一看到回文字符串,脑海里立马要想到前面两个最常用的结题思路:
- 1.动态规划
- 2.中心扩散法
- 3.还有著名的马拉车算法
1.回文子串的个数
、
public class Solution14_回文子串 {
/**
* 方法一:中心扩散法
*/
static int ans = 0;
public static void main(String[] args) throws IOException {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
String s = bf.readLine();
for (int i = 0; i < s.length(); i++) {
//考虑两种情况:aba 和 abba
centerSpread(s, i, i);
centerSpread(s, i, i + 1);
}
System.out.println(ans);
}
//判断回文串的中心扩散法
private static void centerSpread(String s, int left, int right) {
while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
left--;
right++;
ans++;
}
}
//方法二:动态规划
private static int dp(String s) {
int n = s.length(), ans = 0;
boolean[][] dp = new boolean[n][n];
for (int i = n - 1; i >= 0; i--) {
for (int j = i; j < n; j++) {
dp[i][j] = (s.charAt(i) == s.charAt(j)) && (j - i <= 2 || dp[i + 1][j - 1]);
if (dp[i][j]) ans++;
}
}
return ans;
}
}
2.最长回文子串
class Qusetion2 {
//1.动态规划
public static String longestPalindrome(String s) {
int n = s.length();
if (n < 2) return s;
int maxLen = 1;
String res = s.substring(0, 1);
boolean[][] dp = new boolean[n][n];
//左边界一定小于右边界,因此从右边界开始
for (int r = 1; r < n; r++) { //表示右边界
for (int l = 0; l < r; l++) { //表示左边界
// 区间应该慢慢放大
// 状态转移方程:如果头尾字符相等并且中间也是回文
// 在头尾字符相等的前提下,如果收缩以后不构成区间(最多只有 1 个元素),直接返回 True 即可
// 否则要继续看收缩以后的区间的回文性
if (s.charAt(l) == s.charAt(r) && ((r - l) <= 2 || dp[l + 1][r - 1])) {
dp[l][r] = true;
if (r - l + 1 > maxLen) {
maxLen = r - l + 1;
res = s.substring(l, r + 1);
}
}
}
}
return res;
}
//2.中心扩展法
private int start, maxLen;
public String longestPalindrome1(String s) {
if (s == null || s.length() < 2) return s;
for (int i = 0; i < s.length(); i++) {
//考虑中心扩散的两种情况1:aba 和 2: bb
findMaxPalindrome(s, i, i);
findMaxPalindrome(s, i, i + 1);
}
return s.substring(start, start + maxLen);
}
private void findMaxPalindrome(String s, int i, int j) {
while (i >= 0 && j < s.length() && s.charAt(i) == s.charAt(j)) {
i--;//向左延伸
j++;//向右延伸
}
//记录每个起始点扩展的回文串的最大长度
if (maxLen < j - i - 1) {
start = i + 1;
maxLen = j - i - 1;
}
}
}
3.最长不连续回文子串
动态规划解法:dp[l][r]表示从l到r最长回文子串的长度,如果在char[l] == char[r] 那么dp[l + 1][r - 1] + 2 否则最大回文子串要么不包括char[l],要么不包括char[r] ,即在dp[l + 1][r]和dp[l][r - 1]中取最大值
public int longestPalindrome(String s) {
int n = s.length();
int[][] dp = new int[n][n];//dp[l][r]表示l-r中的最长回文串
for (int r = 0; r < n; r++) {
dp[r][r] = 1;
for (int l = r - 1; l >= 0; l--) {
if (s.charAt(l) == s.charAt(r)) {
dp[l][r] = dp[l + 1][r - 1] + 2;
} else {
dp[l][r] = Math.max(dp[l + 1][r], dp[l][r - 1]);
}
}
}
return dp[0][n - 1];
}