剑指 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++; } } }