Loading

回文最少分割数

回文最少分割数

题目:回文最少分割

《程序员代码面试指南》第98题 P314 难度:尉★★☆☆

少有的做不出来的尉难度的题,但是这题在力扣上明明是hard!!!(不懂牛客&这本书怎么把这题定成简单(尉)的)。而且这题明明是动态规划题,却放在了字符串这一章,真的想不到用动态规划去做。就算知道用动态规划去解也做不出来┭┮﹏┭┮

言归正传,书上说,这题是一个经典的动态规划的题目。定义动态规划数组dpdp[i]的含义是子串str[i..len-1]的回文最少分割数。那么dp[0]就是最后的结果

从右往左依次计算dp[i]的值。假设 j 位置处在 i 与 len-1之间(i≤j<len),如果str[i..j]是回文串,那么dp[i]的值可能就是dp[j+1]+1让 j 在 i 到 len-1位置上枚举所有可能情况中的最小值就是dp[i]的值,即dp[i]=min{dp[j+1]+1(i≤j<len,且str[i..j]必须是回文串)}

再定义一个二维数组boolean[][]p,如果p[i][j]为true,说明str[i..j]是回文串。如果p[i][j]为true,一定是以下三种情况

  1. str[i..j]由1个字符组成
  2. str[i..j]由2个字符组成2个字符相等
  3. str[i+1..j-1]是回文串p[i+1][j-1]为true),且str[i]==str[j]

计算dp数组的过程中,位置 i 是从右向左依次计算的。而对每一个 i 来说,又依次从 i 位置向右枚举所有的位置 j(i≤j<len)。所以对p[i][j]来说p[i+1][j-1]的值一定计算过

代码如下:

public int minCut(String str) {
    if (str == null || str.equals("")) {
        return 0;
    }
    char[] chas = str.toCharArray();
    int len = chas.length;
    int[] dp = new int[len + 1];
    dp[len] = -1;
    boolean[][] p = new boolean[len][len];
    for (int i = len - 1; i >= 0; i--) {
        dp[i] = Integer.MAX_VALUE;
        for (int j = i; j < len; j++) {
            if (chas[i] == chas[j] && (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];
}
posted @ 2022-04-12 12:07  幻梦翱翔  阅读(42)  评论(0)    收藏  举报