在最近枯燥的刷题生活中,遇到了许多关于回文子串的问题,这里总结一下。
-
力扣(LeetCode)647 回文子串
- 原题链接
给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。回文字符串 是正着读和倒过来读一样的字符串。子字符串 是字符串中的由连续字符组成的一个序列。具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串
刚开始遇到这种问题最容易想到的是暴力解法,也就是用for循环来遍历字符串判断其子字符串是否是回文串,从而统计数量。但是这种方法时间复杂度较高,容易超时。
对于这样的问题大多可以使用动态规划来分析,其实代码随想录上关于本题也有详细的解答,这里也是参考了其解法。
- 动态规划
class Solution {
public int countSubstrings(String s) {
int len = s.length();
if(len == 0 || s == null) return 0;
if(len<2) return 1;
//设置动规数组
boolean[][] dp = new boolean[len][len];
//每单个字符也是回文串,初始化一下
for(int i = 0;i<len;i++){
dp[i][i] = true;
}
char[] chars = 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 (chars[i] != chars[j]) {
dp[i][j] = false;
} else {
if (j - i < 3) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1];
}
}
}
//统计回文串的数量
int sum = 0;
for(int i = 0;i<len;i++)
for(int j =0;j<len;j++){
if(dp[i][j]){
sum++;
}
}
return sum;
}
}
本题也可以使用双指针法来解决
- 双指针
其实也可以称作为中心扩展,因为解题思想就是从中心出发,向外扩散,看两端的字符是否相等从而来判断是否为回文串。只不过要考虑中心字符为一个和两个的情况。
class Solution {
public int countSubstrings(String s) {
int len = s.length();
int sum = 0;
if(s == null || s.length()<1) return 0;
for(int i = 0;i<len*2-1;i++){
int left = i/2;
int right = left + i%2;
while(left>=0 && right<len && s.charAt(left) == s.charAt(right)){
sum++;
left--;
right++;
}
}
return sum;
}
}
-
力扣(LeetCode)5 最长回文子串
- 原题链接
给你一个字符串 s
,找到 s
中最长的回文子串。如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
该题和上面的回文子串解题方式大致相同,只不过这里需要求的是最长回文子串,以动态规划方式解题为例,我们只需要在遍历的时候维护一个最长长度maxLen变量,不断更新就可以了。
- 动态规划
class Solution {
public String longestPalindrome(String s) {
int len = s.length();
if(len<2) return s;
int maxLen = 1;
int begin = 0;
boolean[][] dp = new boolean[len][len];
for(int i =0;i<len;i++){
dp[i][i] = true;
}
char[] arr = 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(arr[i] != arr[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);
}
}
本博客只作为笔记使用,如有错误还需海涵,也望多多指正