132. 分割回文串 II(两次dp)

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是回文。

返回符合要求的 最少分割次数 。

 

示例 1:

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

输入:s = "a"
输出:0
示例 3:

输入:s = "ab"
输出:1

先从分割回文串I 的方法预处理求出所有回文串。

for(int i = n - 1; i >= 0; i--){
     for(int j = i + 1; j < n; j++){
          f[i][j] = f[i + 1][j - 1] && s[i] == s[j];
     }
}

递推「最小分割次数」思路
我们定义 f[i] 为以下标为 i 的字符作为结尾的最小分割次数,那么最终答案为 f[n - 1]。

不失一般性的考虑第 j 字符的分割方案:

1.从起点字符到第 j 个字符能形成回文串,那么最小分割次数为 0。此时有 f[j] = 0
2.从起点字符到第 j 个字符不能形成回文串:
  1.该字符独立消耗一次分割次数。此时有 f[j] = f[j - 1] + 1
  2.该字符不独立消耗一次分割次数,而是与前面的某个位置 i 形成回文串,[i, j] 作为整体消耗一次分割次数。此时有 f[j] = f[i - 1] + 1
在 2.2 中满足回文要求的位置 i 可能有很多,我们在所有方案中取一个 min 即可。

class Solution {
public:
vector<vector<bool>> f;
    int minCut(string s) {
        int n = s.size();
        f.assign(n,vector<bool>(n,true));
        vector<int> dp(n,INT_MAX); 
        // f[i][j] = (f[i + 1][j - 1] && s[i] == s[j])
        // 预处理
        for(int i = n - 1; i >= 0; i--){
            for(int j = i + 1; j < n; j++){
                f[i][j] = f[i + 1][j - 1] && s[i] == s[j];
            }
        }
        for(int i = 0; i < n; i++){
            if(f[0][i]){
                dp[i] = 0;
                continue;
            }
            for(int j = 0; j < i; j++){
                if(f[j + 1][i])
                    dp[i] = min(dp[i],dp[j] + 1);
            }
        }
        return dp[n - 1];
    }
};

 

posted @ 2021-03-09 15:59  小码农2  阅读(85)  评论(0)    收藏  举报