★647. 回文子串(区间DP)

文章目录

  • [647. 回文子串](https://leetcode.cn/problems/palindromic-substrings/description/)
    • 区间DP的写法
  • ACCode

647. 回文子串

题目不难,但是用到了区间DP的思想。(我是这样用的),顺便复习以下区间dp

区间DP的写法

for(int len=2;len<=n;len++){
	for(int l = 0; l+len-1<n; l++){
		int r = l + len - 1;
		....动态规划状态转移方程。
	}
}

解释一下上面:
区间dp的更新是从小区间扩展到大区间,和动态规划的思想类似,有了小的区间上的值,就可以在这个小的区间上的值根据状态转移方程求得大区间上的值。
区间dp 的写法就是 第一重循环写区间长度, 第二重循环写区间左端点。
这里的 l 就是区间左端点。那这个for循环里 l + len - 1 是怎么来的呢? 为什么是r = l + len - 1呢?
相信推理能力强的小伙伴已经有答案了,for循环里的的l + len - 1就是指的右区间端点值。我们看有没有越界,看的就是右端点。那为什么l + len - 1是右端点呢?
考虑一个非常简单的例子,从2~5之间的左端点是2,右端点是5,一共2 3 4 5 共4个元素,但是呢,右端点减左端点=5-2=3,所以还需要加1才是区间长度:即r - l + 1 = len。所以呢,右端点就是r = l + len - 1。懂了吗?

这个题状态转移方程也是比较好定义的。
题目问是回文串的个数,然后单个的也算回文串,那毫无疑问,我们要设置一个二维的dp。
怎么考虑呢?
f[i][j] 表示什么含义呢?

我们想回文串,一个串是回文的,向外扩展怎么保证他还是回文的呢?那肯定要两个端点处的也是回文串才行。
也就是说 i~j是回文串当且仅当i+1~j-1是回文串且 s.charAt(i) == s.charAt(j)。(为什么是i+1~j-1,你要两边都往里缩,那肯定要都往里了,左端点往右,右端点往左。

所以不妨这样考虑:

设状态转移方程f[l][r] 表示l~r之间是回文串。
所以状态转移方程就是f[l][r] = f[l+1][r-1] && s.charAt(l) == s.charAt(r)

这样就结束了吗 ?
还没有。
你想一下,如果你的长度是2,那l + 1 = r。那也就是,l+1 = r, r- 1 = l,那你想一下f[l+1][r-1]是不是就变成了f[r][l]了?这还了得???所以,这里的dp状态更新的长度要从3开始。那长度为2的怎么办?

还能怎么办? 更新一下就完了! 怎么更新? 长度为2,是回文的,那不就是相邻两个相等吗??这不就解决了吗?

for(int i=0;i+1<s.length();i++)
            if(s.charAt(i) == s.charAt(i+1))
                f[i][i+1] = true;

ACCode

class Solution {
    public int countSubstrings(String s) {
        // f[i][j] 表示下标i~j之间是回文子串
        // f[i][j] = f[i-1][j+1] + 1 if(s[i]==s[j])
        //          = f[i-1][j+1];

        boolean [][] f = new boolean [s.length()+1][s.length()+1];
        for(int i=0;i<s.length();i++)
            f[i][i]=  true;
        for(int i=0;i+1<s.length();i++)
            if(s.charAt(i) == s.charAt(i+1))
                f[i][i+1] = true;
        int n = s.length();
        for(int len=3;len<=s.length();len++) {
            for(int l=0;l+len-1<s.length();l++){
                int r = l + len - 1;
               f[l][r] = f[l+1][r-1] && s.charAt(l) == s.charAt(r);
            }
        }
            System.out.println("afaf");
        int cnt = 0;
        for(int i=0;i<s.length()+1; i++){
            for(int j=0;j<s.length()+1;j++){
                System.out.print(f[i][j] + " ");
                if(f[i][j]) cnt++;
            }
            System.out.println();
        }
        System.out.println(cnt);

        return cnt;
    }
}

你可能感兴趣的:(力扣Hot100,排序算法,算法,数据结构,动态规划)