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.
将一个字符串切分成多个字符串,使得切分后的每个字符串都是回文串,求最少的切分次数。
最容易想到的是用递归缩小问题规模minCut(s) =min(∑ { minCut(1+s.sub(i,s.len)} ),
从左往右搜索,找到第一个可以cut的位置,然后递归。
public int minCut(String s) {
if(s == null || "".equals(s) || s.length() ==1 || isPalindrome(s)){
return 0;
}
int min = Integer.MAX_VALUE;
for(int i=1;i<s.length();i++){
if(isPalindrome(s.substring(0, i))){
int curCut = 1 + minCut(s.substring(i,s.length()));
min = curCut < min ? curCut : min;
}
}
return min;
}
public boolean isPalindrome(String s){
if(s == null || "".equals(s) || s.length() ==1){
return true;
}
for(int i=0;i<s.length()/2;i++){
if(s.charAt(i) != s.charAt(s.length()-1-i)){
return false;
}
}
return true;
}
这种迭代没有剪枝,不出意外地超时了。
下面想想如何剪枝:
由于是从头循环到尾,后面的子串很多计算都是重复的,要做的就是把这些子串计算能够存下来,那么可以用一个数组dp[i]存储
令dp[i]表示[i,s.len-1]切的次数,那么当[i,j]是回文时,dp[i]=dp[j+1]+1
按此种优化如下:
public int minCut(String s) {
int len = s.length();
if (len < 2) {
return 0;
}
int[] dp = new int[len + 1];
boolean[][] isPalindrome = new boolean[len + 1][len + 1];
for (int i = 0; i < len; i ++) {
dp[i] = len - i - 1;
isPalindrome[i][i] = true;
}
dp[len] = -1;
for (int i = len - 1; i >= 0; i --) {
for (int j = i; j < len; j ++) {
if (s.charAt(i) == s.charAt(j)
&& (i+1>=j || isPalindrome[i + 1][j - 1])) {
dp[i] = Math.min(dp[i], dp[j + 1] + 1);
isPalindrome[i][j] = true;
}
}
}
return dp[0];
}
这里的二维数组isPalindrome[i][j]存储subStr[i,j]是否回文串,用空间换时间,避免了从i到j整个搜索