字符串经过最少切割次数,使得切割后的每个字串都是回文串

题目描述

给出一个字符串s,分割s使得分割出的每一个子串都是回文串

计算将字符串s分割成回文分割结果的最小切割数

例如:给定字符串s=“aab”,

返回1,因为回文分割结果[“aa”,“b”]是切割一次生成的。

分析

设置两个变量 i 和 j,i 从字符串最后一个字符开始向前走,j 从 i 开始往后走到字符串结尾。设置数组dp[i]代表从 i 到s.length-1这段字符串要分割的最小次数,p[i][j]代表从i 到 j 的这一段字符串是不是回文串。如果 i 到 j 之间是回文,那就要找到 j+1到字符串最后的字符串分割成回文串的最小次数也就是p[j+1]。因当i=s.length-1,j=i,要找到p[i+1],所以p数组的大小是s.length+1,这也是为什么要从后往前算。
代码不易理解,根据例子s="aab"说一下:
置p[3]=-1
i = 2
…j = 2, 成回文,p[2] = p[3]+1 = 0 不用分割
i = 1
…j = 1,成回文,p[1] = p[2]+1 = 1
…j = 2, 不成回文,不操作
…最后p[1] = 1
i = 0
…j = 0, 回文,p[0] = p[1]+1 = 2
…j = 1, 回文,p[0] = min{p[0], p[2]+1} = 1
…j = 2, 不成回文,不操作
最后得出p[0]=1,即需要切割至少1次使其字串都是回文串
总结一下就是找到从i到s.length-1之间最小的分割次数,而更长串的分割次数由其字串的分割此处通过一定转换得来,所以串必须从短到长计算最小分割次数。

状态转移方程:当i..j是回文, p[i] = min{p[i], p[j+1]+1}
判断i..j是不是回文:s.charAt[i]=s.charAt[j],且i和j是同一个或连在一起 或者 若不是以上情况则i+1..j-1是回文,也有套用子问题,因此还要维护dp[i][j]

代码

public class Solution {
    public int minCut(String s) {
        int l = s.length();
        if(l<2)return 0;
        int [] dp = new int[l+1];
        boolean [][] p = new boolean[l][l];
        dp[l] = -1;//为了使当j=s.length()-1时依然是回文,要p[j+1]+1=0
        for(int i=l-1; i>=0; i--){
            dp[i] = Integer.MAX_VALUE;
            //如果i..j是回文,找到最小的dp[j+1]+1
            for(int j=i; j<l;j++){
                if(s.charAt(j)==s.charAt(i) && (j-i<2 || p[i+1][j-1])){
                    p[i][j] = true;
                    dp[i] = Math.min(dp[i], dp[j+1]+1);
                }
            }
        }
        return dp[0];
    }
}

你可能感兴趣的:(leetcode)