思路
1.dp
布尔类型的dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串,如果是dp[i][j]为true,否则为false。
当s[i]与s[j]不相等,那没啥好说的了,dp[i][j]一定是false。
当s[i]与s[j]相等时,这就复杂一些了,有如下三种情况
- 情况一:下标i 与 j相同,同一个字符例如a,当然是回文子串
- 情况二:下标i 与 j相差为1,例如aa,也是回文子串
- 情况三:下标:i 与 j相差大于1的时候,例如cabac,此时s[i]与s[j]已经相同了,我们看i到j区间是不是回文子串就看aba是不是回文就可以了,那么aba的区间就是 i+1 与 j-1区间,这个区间是不是回文就看dp[i + 1][j - 1]是否为true。
- 时间复杂度:$O(n^2)$
空间复杂度:$O(n^2)$
var countSubstrings = function(s) {
// dp解法
// dp[i][j],s[i]-s[j]是不是回文子串,两端闭合
let dp =Array.from(Array(s.length),()=>Array(s.length).fill(false))
let result =0
// 先遍历列,再遍历行,保证递推的来源dp[i+1][j-1]是先被计算
for(let j=0;j<s.length;j++){
for(let i=0;i<=j;i++){
if(s[i]===s[j]){
if(j-i<=1){
// s[i]-s[j]长度为1 or 2,此时一定是回文
dp[i][j]=true
}else{
// 否则判断中间的i+1 到 j-1这中间子串是不是回文,递推
dp[i][j] =dp[i+1][j-1]
}
result += dp[i][j]?1 :0
}
}
}
return result
};
2. 中心扩散法
分别讨论
var countSubstrings = function(s) { // 中心扩散法 let result =0 const findPalindrome =function(s,left,right){ let res =0 while(left>=0&&right<s.length&&s[left]===s[right]){ res++ left-- right++ } return res } for(let i=0;i<s.length;i++){ // 当中心为1个时 result+=findPalindrome(s,i,i) // 当中心为2个时 result+= findPalindrome(s,i,i+1) } return result };
时间复杂度:$O(n^2)$
- 空间复杂度:$O(1)$
统一讨论
这种可以将left和right统一起来,循环次数时 2^n -1(因为有n个单独中心和 n-1个双中心)
我觉得不是很好理解,3.Manacher(马拉车)算法
4. 暴力(n^3超时)