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.
分析:
动态规划
看到最小切割数,首先想到动态规划,之后像怎么提取子问题以及怎么由子问题推出最终问题答案。
假设字符串长度为len
子问题:从 i 到 n-1 的最小切割数,设为cuts[i], 可知,cuts[n-1]=0,因为只有一个字符,初始,cuts[ i ] = len - i -1, 即初始认为只有每一个字符才是一个回文;
状态转移方程: 假设区间 [ i, j ] 上的子串是回文,则 i 处的切割只要在j+1处的最小切割数加1,cuts[i] = min { cuts[i], cuts[j+1]+1 },
那么,最后cuts[0]就是最后的结果。
怎么判断字符串是不是回文?
最原始的想法:如果想判断 [ i, j ] 是不是回文,则如果 [i+1, j-1] 是回文, 并且,i, j 位置的字符相等,则 [ i, j ]是回文。
这样的想法首先会想到递归,中介条件是 j-i < 2, 即 i, j 在同一个位置或者相邻。
在递归中,每次都要求解某个区间是不是回文,产生重复子问题,于是想到用动态规划。
用 mat [ i ][ j ] 来表示,区间 [ i, j ] 是不是回文,记录中间结果。
则,如果 mat [ i+1 ][ j-1 ]为true, 同时 i, j 位置字符相等, 则 mat [ i ][ j ] = true.
几个问题:
为什么cuts的长度是 len+1 ?
因为我们要根据状态转移方程计算cuts[len-1],就需要cuts[len]的值。
为什么cuts[len]的值为 -1 ?
因为要满足 cuts[len-1] = cuts[len]。
我看到很多解法是让 cut[len] = 0, cuts[len-1] = 1, 到最后返回cuts[0]-1 都可以得到正确答案,但是从实际意义上却不好理解。既然cuts[i] 表示从字符 i 到末尾的最小切割术,则我们知道 cuts[len-1], 即最后一个字符的最小切割术一定是0,同时从物理意义上来讲,我们最后应该返回从字符0到最后的最小切割数,即cuts[0].
同时,可以认为 位置 len 到最后是一个空串,空串返回-1也是合理的。
基于以上考虑,我认为应该让 cuts[len-1] = 0, cuts[len] = -1.
public class Solution {
public int minCut(String s) {
int len = s.length();
boolean[][] matrix = new boolean[len][len];
int cuts[] = new int[len+1];
//初始化cuts,在每一个字符处都切一下
for(int i=0; i<=len; i++)
cuts[i] = len-i-1;
//更新从i到最后的状态
for(int i=len-1; i>=0; i--){
for(int j=i; j<len; j++){
if( (s.charAt(i) == s.charAt(j)&&(j-i<2))
|| (s.charAt(i) == s.charAt(j)&& matrix[i+1][j-1]) ){
matrix[i][j] = true;
cuts[i] = Math.min(cuts[i], cuts[j+1]+1);
}
}
}
return cuts[0];
}
}