We want to partition the string into the minimum number of cuts so that every substring is a palindrome. Dynamic programming helps us efficiently check all possible partitions and track the minimum cuts needed for each prefix.
classSolution {
publicintminCut(String s) {
int n = s.length();
boolean[][] dp =newboolean[n][n];
int[] cut =newint[n];
for (int j = 0; j < n; j++) {
cut[j]= j;
for (int i = 0; i <= j; i++) {
if (s.charAt(i) == s.charAt(j) && (j - i <= 1 || dp[i+1][j-1])) {
dp[i][j]=true;
if (i == 0) {
cut[j]= 0;
} else {
cut[j]= Math.min(cut[j], cut[i-1]+ 1);
}
}
}
}
return cut[n-1];
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
classSolution:
defminCut(self, s: str) -> int:
n = len(s)
dp = [[False]*n for _ in range(n)]
cut = [i for i in range(n)]
for j in range(n):
for i in range(j+1):
if s[i] == s[j] and (j-i <=1or dp[i+1][j-1]):
dp[i][j] =Trueif i ==0:
cut[j] =0else:
cut[j] = min(cut[j], cut[i-1]+1)
return cut[-1]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
classSolution {
public:int minCut(string s) {
int n = s.size();
vector<vector<bool>> dp(n, vector<bool>(n, false));
vector<int> cut(n);
for (int j =0; j < n; ++j) {
cut[j] = j;
for (int i =0; i <= j; ++i) {
if (s[i] == s[j] && (j - i <=1|| dp[i+1][j-1])) {
dp[i][j] = true;
if (i ==0) cut[j] =0;
else cut[j] = min(cut[j], cut[i-1] +1);
}
}
}
return cut[n-1];
}
};
This divide-and-conquer algorithm utilize the symmetry of palindromes, so there is no need to cache the result of whether s[i:j] is a palindrome.
Say that it started at s[i] = 'b', and s[i-1,i+1] is a palindrome “aba”:
1
2
3
.......aba...
|<-X->| ^
|<---Y-->|
And we know the least cuts for s[0,i-1] is X, then the least cuts for s[0,i+1] Y is not greater than X+1. Last, we need to find out all the palindromes in s[0,i+1] so as to minimize the number of cuts.
Explanation 2:
The definition of ‘cut’ array is the minimum number of cuts of a sub string. More specifically, cut[n] stores the cut number of string s[0, n-1].
Here is the basic idea of the solution:
Initialize the ‘cut’ array: For a string with n characters s[0, n-1], it needs at most n-1 cut. Therefore, the ‘cut’ array is initialized as cut[i] = i-1
Use two variables in two loops to represent a palindrome:
The external loop variable ‘i’ represents the center of the palindrome. The internal loop variable ‘j’ represents the ‘radius’ of the palindrome. Apparently, j <= i is a must.
This palindrome can then be represented as s[i-j, i+j]. If this string is indeed a palindrome, then one possible value of cut[i+j] is cut[i-j] + 1, where cut[i-j] corresponds to s[0, i-j-1] and 1 correspond to the palindrome s[i-j, i+j];
When the loops finish, you’ll get the answer at cut[s.length]
1
2
3
4
if isPalindrome(i, j)
T[i][j] = 0;
else
T[i][j] = 1 + min(T[i][k] + T[k+1][j]) ; where k = i,..,j-1.