LeetCode 647. 回文子串
题目链接
题目分析
这个题和那个最长回文子串一个道理,可以用中心扩展方法或者DP方法进行处理,这个题我优先使用了DP进行处理。
DP方法
由题目可知,我们每个字符都能成为一个单独的回文串,所以count初始值就应该为字符串的长度。
然后我们定义一个boolean的二维数组,其定义如下:
- dp[i][j]代表字符串从i到j能否构成一个回文串
然后剩下的办法就很容易了,其状态转移方程如下:
- 如果s[i] == s[j] 且 i == j -1 或者 dp[i+1][j-1] 的情况下,count自增,然后把当前dp[i][j]设置为true
i == j-1是因为如果这两个是相邻的情况下,直接就能构成新的回文串,直接判对即可。
dp[i+1][j-1]是因为如果当前位置要成为新回文串的话,那么其字串也应该为回文串。
这些都做完了,也代表base cases也出来了,我们利用二维数组的左下角,对角线元素应该都为true。
中心扩展方法
思想就是跟最长回文串一样,我们拿每一个元素作为起始点,然后以该点为起始点向左右两边扩展,扩展的条件为
- left >= 0 && right < s.length()
- s[left] == s[right]
满足以上条件,我们就把计数器加一,然后left--, right++。
当然这个方法需要分为回文串为奇数和回文串为偶数长度的情况。
这个方法应该是最容易实现的了。
代码实现
动态规划代码
class Solution {
public int countSubstrings(String s) {
int count = s.length();
char[] str = s.toCharArray();
boolean[][] dp = new boolean[s.length()][s.length()];
for(int i = 1; i < s.length(); i++){
dp[i][i] = true;
}
for(int j = 0; j < s.length(); j++){
for(int i = j-1; i >= 0; i--){
if(str[i] == str[j] && (i == j -1 || dp[i+1][j-1])){
dp[i][j] = true;
count++;
}
}
}
return count;
}
}
中心扩展代码
class Solution {
int num = 0;
public int countSubstrings(String s) {
for (int i=0; i < s.length(); i++){
count(s, i, i);//回文串长度为奇数
count(s, i, i+1);//回文串长度为偶数
}
return num;
}
public void count(String s, int start, int end){
while(start >= 0 && end < s.length() && s.charAt(start) == s.charAt(end)){
num++;
start--;
end++;
}
}
}