给你一个字符串 s
,请你将 s
分割成一些子串,使每个子串都是回文串
返回符合要求的 最少分割次数 。
示例 1:
输入:s = "aab" 输出:1 解释:只需一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。
示例 2:
输入:s = "a" 输出:0
示例 3:
输入:s = "ab" 输出:1
解题思路:动态规划
首先在这题中我们定义一个ans[]数组,ans[i]表示前i个字符满足题目条件的最少切割次数。我们知道单一字符一定是一个回文串,因此ans[1]=0。对于ans[2],考虑前两个字符的情况,如果这两个字符组成的字符串是回文串那么ans[2]=0,如果不是回文串,那么对这两个字符组成的字符串进行切割,切割为两个单一字符,第一个单一字符的切割次数就是ans[1],后面单一字符也一定是回文串,只需要+1即可,即ans[2]=ans[1]+1;综合这两种情况我们可以得出ans[2]=min(ans[1]+1,0);
ans[3]考虑前三个字符的情况,如果整体是回文串,那么ans[3]=0;如果不是,那么将这三个字符切割,这里有两种切割方法,1 | 23和12 | 3,第一种切割方式就需要判断23是否为回文串;第二种切割方式就是ans[2]+1……
整体流程:
* 1、先判断整个字符串是否为回文串,是那么就是0
* 2、ans[i]=min(ans[j]+1) j<i
* 意思是:如①ans[4] 需要考虑ans[3]+1、② ans[2]和后面两个字符是否为回文(是的话就+1,不是就不能这么分)③ans[1]和后面三个字符是否问回文(同理)
*3、在2的基础上,比对最小的即是ans[4]的值
依据这种情况,我们能够得出状态转移方程:
j<i && [j+1,i]是回文串: ans[i] = min(ans[j]+1)
[1,i]是回文串: ans[i]=0;
// 最小切割次数
public static int minCut(String s) {
int n=s.length();
if(n == 0 ) return 0;
if(judge(s,0,n-1)) return 0; // 如果整体都是回文串,那么返回0
int []ans=new int[n+1]; // 定义ans数组:ans[i]表示前i个字符最小的分割次数
for(int i=1;i<=n;i++){
ans[i]=i-1; //初始化为最大次数
}
for(int i=2;i<=n;i++){
// 整体为回文串
if(judge(s,0,i-1)){
ans[i]=0;
continue;
}
// 如果不是那么进行下面判断
//j<i && [j+1,i]这几个字符是否为 回文串
for(int j=1;j<i;j++){
if(judge(s,j,i-1)){
ans[i]=Math.min(ans[i], ans[j]+1);
}
}
}
return ans[n];
}
// 用来判断是否是回文串
public static boolean judge(String s,int start,int end){
while(start<end){
if(s.charAt(start)!=s.charAt(end)){
return false;
}else{
start++;
end--;
}
}
return true;
}