Welcome to Subscribe On Youtube
Question
Formatted question description: https://leetcode.ca/all/132.html
132 Palindrome Partitioning II
Given a string s, partition s such that every substring of the partition is a palindrome.
Return the minimum cuts needed for a palindrome partitioning of s.
For example, given s = "aab",
Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.
@tag-dp
Algorithm
One-dimensional dp array, where dp[i]
represents the minimum number of divisions in the range of substring [0, i]
.
Use a two-dimensional dp array p
, where p[i][j]
indicates whether the substring in the interval [i, j]
is a palindrome, and the state transition equation is p[i][j] = (s[i] == s[j]) && p[i+1][j-1]
, where p[i][j] = true
if [i, j]
is a palindrome.
Code
-
public class Palindrome_Partitioning_II { /* * @note: 这题,我自己的思路有了点问题。如果i-j是pal,那么i的cut数应该是j+1的cut数加1。 * 我想成了i的cut数等于j的cut数,逻辑错误 * * 这题最好的地方,是用了两个dp的数组,一个标记是不是pal,一个数cut的数目 而不是单纯的一个dp数组 */ public class Solution { public int minCut(String s) { if (s == null || s.length() == 0) { return -1; } // 'abcba', when reaching 'c', minCut=2 // when reaching 2nd 'b', minCut=1 // when reaching 2nd 'a', minCut=0 // so, if a substring is palindrome, cut is prev_segment+1 // set up a fast lookup for if palindrome from i to j boolean[][] isPal = new boolean[s.length()][s.length()]; for (int i = 0; i < s.length(); i++) { for (int j = i; j >= 0; j--) { if (i == j || (s.charAt(i) == s.charAt(j) && (i - j == 1 || isPal[j + 1][i - 1]))) { isPal[j][i] = true; // j is first, then i } } } // set up min count array, worst case, each char is a palindrome int[] minCut = new int[s.length()]; for (int i = 0; i < s.length(); i++) { minCut[i] = i; } // how to cound, eg: 'aabcba', 'aabcbaz' // @note: if a substring is palindrome, cut is prev_segment+1 for (int i = 0; i < s.length(); i++) { for (int j = 0; j < s.length(); j++) { if (isPal[i][j]) { if (i - 1 >= 0) { // @note: eg, 'aabcba' minCut[j] = Math.min(minCut[j], 1 + minCut[i - 1]); } else { // i.e., i==0. eg, 'abcba' minCut[j] = 0; } } } } int min = minCut[s.length() - 1]; return min; } } public class Solution_slow { List<List<String>> list = new ArrayList<>(); public int minCut(String s) { if (s == null || s.length() == 0) { return -1; } find(s, new ArrayList<String>()); int min = Integer.MAX_VALUE; for (List<String> each : list) { min = Math.min(min, each.size() - 1); } return min; } private void find(String s, ArrayList<String> currentList) { if (s.length() == 0) { list.add(currentList); return; } // idea is, scan from index=0, to find each palindrome, then rest substring to next recursion for (int i = 0; i < s.length(); i++) { String sub = s.substring(0, i + 1); // @note: substring 0-s[i] System.out.println("substring is: " + sub); if (isPal(sub)) { ArrayList<String> nextList = new ArrayList<>(currentList); // deep copy nextList.add(sub); find(s.substring(i + 1), nextList); } } } private boolean isPal(String s) { int i = 0; int j = s.length() - 1; while (i <= j) { if (s.charAt(i) != s.charAt(j)) { return false; } i++; j--; } return true; } } }
-
class Solution { public: int minCut(string s) { int n = s.size(); vector<vector<bool>> dp1(n, vector<bool>(n)); for (int i = n - 1; i >= 0; --i) { for (int j = i; j < n; ++j) { dp1[i][j] = s[i] == s[j] && (j - i < 3 || dp1[i + 1][j - 1]); } } vector<int> dp2(n); for (int i = 0; i < n; ++i) { if (!dp1[0][i]) { dp2[i] = i; for (int j = 1; j <= i; ++j) { if (dp1[j][i]) { dp2[i] = min(dp2[i], dp2[j - 1] + 1); } } } } return dp2[n - 1]; } };
-
class Solution: def minCut(self, s: str) -> int: n = len(s) dp1 = [[False] * n for _ in range(n)] for i in range(n - 1, -1, -1): for j in range(i, n): dp1[i][j] = s[i] == s[j] and (j - i < 3 or dp1[i + 1][j - 1]) dp2 = [i for i in range(n)] for i in range(n): for j in range(0, i + 1): if dp1[j][i]: dp2[i] = min(dp2[i], dp2[j - 1] + 1) if j > 0 else 0 return dp2[-1] class Solution: def minCut(self, s: str) -> int: @cache def dfs(i): if i >= n - 1: return 0 ans = inf for j in range(i, n): if g[i][j]: ans = min(ans, dfs(j + 1) + (j < n - 1)) return ans n = len(s) g = [[True] * n for _ in range(n)] for i in range(n - 1, -1, -1): for j in range(i + 1, n): g[i][j] = s[i] == s[j] and g[i + 1][j - 1] ans = dfs(0) dfs.cache_clear() return ans ############# class Solution(object): def minCut(self, s): """ :type s: str :rtype: int """ pal = [[False for j in range(0, len(s))] for i in range(0, len(s))] dp = [len(s) for _ in range(0, len(s) + 1)] for i in range(0, len(s)): for j in range(0, i + 1): if (s[i] == s[j]) and ((j + 1 > i - 1) or (pal[i - 1][j + 1])): pal[i][j] = True dp[i + 1] = min(dp[i + 1], dp[j] + 1) if j != 0 else 0 return dp[-1]