1、看到子串,首先就会想到动态规划,对于回文子串,存在如下规律,当s[i]==s[j],同时s[i+1]到s[j-1]之间的字符串满足回文子串,那么s[i]到s[j]之间就同样是回文子串。因此构建二维布尔型数组dp,其中dp[i][j]表示,i到j之间是否构成回文子串,初始化对角线均为true,因为dp[i][j](i==j)必然为回文子串。采用暴力解法,假设回文字符子串个数为res(初始化为s的长度,因为每一个单独的字符必然是一个回文子串),对数组进行双重遍历,对于每一个s[i],遍历位于i之后其余字符s[j](j>i),判断s[i][j] 是否为回文字符串,如果是的话,res++。最后返回res,即为所求的回文子串个数。
但按照上述想法在测试的时候却发生如下错误,以字符串“aaaaa”为例。从s[0]开始,当 j==3 时,明显s[0:3]为回文子串,根据上述的判断条件需要满足 s[0]==s[3] && (3-0==1 || dp[1][2]==true),但是因为还没有对i==1的情况进行遍历,所以此时dp[1][2]==false,不满足条件,s[0:3]无法被正确判断,造成错误。
因此修改思路,同样i从0开始遍历,但j不再是i之后的所有字符,而替换为表示子串长度的step,即判断从每一字符开始,长度为step的子串是否为回文子串,这样就不会存在上述的问题,最后实现代码如下:
func countSubstrings(s string) int {
var tmpS []rune=[]rune(s)
var res, lenS int=len(tmpS), len(tmpS)
var dp [][]bool=make([][]bool, lenS)
for i:=0; i<lenS; i++ {
dp[i]=make([]bool, lenS)
dp[i][i]=true
}
for step:=1; step<lenS; step++{
for i:=0; i+step<lenS; i++ {
if tmpS[i]==tmpS[i+step] && (step==1 || dp[i+1][i+step-1]){
dp[i][i+step]=true
res++
}
}
}
return res
}