力扣132. 分割回文串 II

题目链接

给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回符合要求的最少分割次数。

输入: "aab"
输出: 1
解释: 进行一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。

分析:
如果按照上一题的写法,应该是求出来所有方案,然后求一下每个List中的元素个数,取一个min再减一就是答案。但是我估计大概率超时。

思路:通过dp,用 dp[i] 表示前 i 个数分割成每个子串都是回文串至少分出多少个(即答案数 + 1)
状态转移:可以枚举 i 前面的点,假设 j 是 i 前面的某个点,那dp[j]就表示前 j 个字符分割成每个字符串都是回文串最少分出多少个。如果 j ~ i 这一段是回文串,那么只需要多切一次,即 dp[i] = dp[j] + 1,将 j 从头枚举到 i 取最小值即可。
一开始我认为如果从 1 ~ i 这一段本身就是个回文串,那么不属于上述的情况,后面发现也属于,因为初始化合法,dp[0] = 0,前0个字符自然不需要切割,那个数一定为0个。如果 1 ~ i 本身是回文串,那就会走 dp[0] + 1,自然就是1。

class Solution {
    
    
    public int minCut(String s) {
    
    
        int n = s.length();
        boolean[][] f = new boolean[n + 1][n + 1];
        s = " " + s; // dp从1开始比较舒服,不用处理0的特殊情况
        for (int j = 1; j <= n; j ++ ) // 预处理看是不是回文串
            for (int i = 1; i <= j; i ++ )
                if (i == j) f[i][j] = true;
                else if (s.charAt(i) == s.charAt(j)) {
    
    
                    if (i + 1 == j || f[i + 1][j - 1]) f[i][j] = true;
                }
                
        int[] dp = new int[n + 1];
        // 先初始无穷大,只有前0个是0
        for (int i = 0; i < n + 1; i ++ ) dp[i] = 100000000;
        dp[0] = 0;
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= i; j ++ )
                if (f[j][i]) // 如果 j ~ i 是回文串
                    dp[i] = Math.min(dp[i], dp[j - 1] + 1);
        return dp[n] - 1;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43795939/article/details/114267061