132-Palindrome-Partitioning-II
0x0 题目详情
0x1 解题思路
0x2 代码实现
class Solution {
public int minCut(String s) {
if(s==null || s.length()==0){
return 0;
}
int result=Integer.MAX_VALUE;
char[] chr=transform(s);
int[] pArr=new int[chr.length];
manacher(pArr,chr);
int[] dp=new int[chr.length];
//非常重要!!!对数组的初始化
//最差情况,每个地方都需要切割
for(int i=1;i<chr.length;i++){
dp[i]=i;
}
for(int len=1;len<chr.length;len++){
//过滤left指向的字符为#的情况
if(chr[len]=='#'){
continue;
//如果i左侧的字符串已经构成了回文串,那么就不需要判断了,切割次数就是0
}else if(judge(pArr,1,len)){
dp[len]=0;
continue;
}
//遍历i左侧的每一个切割点
for(int j=1;j<len;j++){
//同样过滤j指向的字符为#的情况
if(chr[j]=='#'){
continue;
}
if(judge(pArr,j+2,len)){
dp[len]=Math.min(dp[len],dp[j]+1);
}
}
}
return dp[chr.length-2];
}
private char[] transform(String s){
char[] str=s.toCharArray();
char[] result=new char[str.length*2+1];
int index=0;
for(int i=0;i<result.length;i++){
if((i&1)==0){
result[i]='#';
}else{
result[i]=str[index];
index++;
}
}
return result;
}
//判断[left,right]是否为回文串
//以字符串#a#b#a#,这里的right使用的是从left开始需要判断的字符串的长度
//这里right指向#时并不会对结果产生影响,因为这里已经过滤了left指向#的情况
//pArr是最大回文半径数组
private boolean judge(int[] pArr,int left,int right){
int mid=left+(right-left)/2;
//中点处的回文半径要能够覆盖left,才说明[left,right]为一个回文串
return mid-pArr[mid]<left?true:false;
}
//chr不可能为null或者长度为0
private void manacher(int[] pArr,char[] chr){
//最大回文右边界
int R=-1;
//中心,包括自己
int C=-1;
for(int i=0;i<chr.length;i++){
pArr[i]=R>i?Math.min(pArr[2*C-i],R-i):1;
while(i-pArr[i]>-1 && i+pArr[i]<chr.length){
if(chr[i-pArr[i]]==chr[i+pArr[i]]){
pArr[i]++;
}else{
break;
}
}
if(i+pArr[i]>R){
R=i+pArr[i];
C=i;
}
}
}
}0x3 课后总结
Last updated