方法一:暴力求解(O(n^3))
class Solution {
public int countSubstrings(String s) {
int n = s.length();
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (satisfy(s.substring(i, j))) {
ans++;
}
}
}
return ans;
}
public boolean satisfy(String s) {
int i = 0, j = s.length() - 1;
while (i < j) {
if (s.charAt(i) != s.charAt(j)) return false;
i++;
j--;
}
return true;
}
}
方法二:动态规划(O(n^2))
①确定状态:dp[i][j]表示[i, j]的字符串是否为回文子串;
②转移方程:if (s.charAt(i) == s.charAt(j) && (j - i <= 2 || dp[i + 1][j - 1])) {
dp[i][j] = true;
};
③初始条件和边界情况:dp[i][j] = false;
④计算顺序:因为dp[i][j] 由 dp[i + 1][j - 1] 推出,所以外层for循环倒序,内层for循环正序。
class Solution {
public int countSubstrings(String s) {
int n = s.length();
//dp[i][j]表示[i,j]的字符串是否为回文子串
boolean[][] dp = new boolean[n][n];
int ans = 0;
//因为求dp[i][j]需要知道dp[i + 1][j - 1]
//所以外层循环需要倒着写(i--),内层循环需要正着写(j++)
for (int i = n - 1; i >= 0; i--) {
for (int j = i; j < n; j++) {
//当s.charAt(i) != s.charAt(j)时,dp[i][j]一定为false
//当s.charAt(i) == s.charAt(j)且元素个数为1,2,3或dp[i + 1][j - 1]为true时,dp[i][j]一定为true
if (s.charAt(i) == s.charAt(j) && (j - i <= 2 || dp[i + 1][j - 1])) {
dp[i][j] = true;
ans++;
}
}
}
return ans;
}
}
方法三:中心拓展(O(n^2))
class Solution {
public int countSubstrings(String s) {
int n = s.length();
int ans = 0;
for (int i = 0; i < n; i++) {
//j = 0,回文中心是一个字符
//j = 1,回文中心是两个字符
for (int j = 0; j <= 1; j++) {
int left = i;
int right = i + j;
while (left >= 0 && right < n && s.charAt(left) == s.charAt(right)) {
left--;
right++;
ans++;
}
}
}
return ans;
}
}