剑指 Offer II 094. 最少回文分割(132. 分割回文串 II)

题目:

思路:

【1】动态规划

代码展示:

动态规划:

//时间30 ms击败45.38%
//内存47.4 MB击败11.31%
//时间复杂度:O(n^2),其中 n 是字符串 s 的长度。预处理计算 g 和动态规划计算 f 的时间复杂度均为 O(n^2)。
//空间复杂度:O(n^2),数组 g 需要使用 O(n^2) 的空间,数组 f 需要使用 O(n) 的空间
class Solution {
    public int minCut(String s) {
        int n = s.length();
        boolean[][] g = new boolean[n][n];
        for (int i = 0; i < n; ++i) {
            Arrays.fill(g[i], true);
        }

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

        int[] f = new int[n];
        Arrays.fill(f, Integer.MAX_VALUE);
        for (int i = 0; i < n; ++i) {
            if (g[0][i]) {
                f[i] = 0;
            } else {
                for (int j = 0; j < i; ++j) {
                    if (g[j + 1][i]) {
                        f[i] = Math.min(f[i], f[j] + 1);
                    }
                }
            }
        }

        return f[n - 1];
    }
}

//时间20 ms击败76.83%
//内存47.5 MB击败9.38%
class Solution {
    public int minCut(String s) {
        boolean[][] dp = new boolean[s.length()][s.length()];
        for (int i = 0; i < s.length(); i++) {
            for (int j = i; j >= 0; j--) {
                if (s.charAt(i) == s.charAt(j) && (i - j <= 1 || dp[i - 1][j + 1])) {
                    dp[i][j] = true;
                }
            }
        }
        int[] newDp = new int[s.length() + 1];
        Arrays.fill(newDp, 2000);
        newDp[0] = 0;
        for (int i = 1; i < s.length() + 1; i++) {
            for (int j = 1; j <= i; j++) {
                if (dp[i - 1][j - 1]) {
                    newDp[i] = Math.min(newDp[i], newDp[j-1] + 1);
                }
            }
        }

        return newDp[s.length()] - 1;
    }
}

//时间6 ms击败97.38%
//内存39.6 MB击败85.52%
class Solution {
    public int minCut(String s) {
        int n = s.length();
        //dp[i] 表示以以s[i]为结尾的字串的最少分割次数
        int[] dp = new int[n + 1];
        Arrays.fill(dp, Integer.MAX_VALUE);
        dp[0] = -1;
        //枚举中心点
        for(int center = 0; center < 2 * n - 1; center++){
            int left = center / 2;
            int right = left + center % 2;
            while(left >= 0 && right < n && s.charAt(left) == s.charAt(right)){
                dp[right + 1] = Math.min(dp[right + 1], dp[left] + 1);
                left--;
                right++;
            }
        }
        return dp[n];
    }
}

//时间1 ms击败100%
//内存39.6 MB击败85.79%
class Solution {

    // dp[i] 表示0-i字符串最少分割次数为 dp[i]
    int[] dp;
    public int minCut(String s) {
        int n = s.length();
        dp = new int[n];
        char[] arr = s.toCharArray();
        // 初始化大一点的值,否则取最小值就全为0了
        for(int i = 1; i < n; i++) dp[i] = n;
        for(int i = 0; i < n; i++){
            // 奇数位字符串
            centerExpand(arr, i, i);
            // 偶数位字符串
            centerExpand(arr, i, i + 1);
        }
        return dp[n - 1];
    }

    // 中心扩散
    public void centerExpand(char[] arr, int l, int r){
        while(l >= 0 && r < arr.length && arr[l] == arr[r]){
              // 扩散到字符串头当前不需要切割  
              if(l == 0){
                  dp[r] = 0;
              }else{
                  // 否则, 当前切割次数 与 上一次切割次数 + 1 取最小值
                  dp[r] = Math.min(dp[r], dp[l - 1] + 1);  
              } 
              l--;
              r++;
        }
    }
}

 

posted @ 2023-05-11 12:17  忧愁的chafry  阅读(11)  评论(0编辑  收藏  举报