136. 切割回文串
描述
给定一个字符串s,将s分割成一些子串,使每个子串都是回文串。
返回s所有可能的回文串分割方案。
样例
给出 s = "aab"
,返回
[
["aa", "b"],
["a", "a", "b"]
]
分析:本题采用回溯法,深度优先遍历字符串。注意保存子结果的条件以及每次返回上一层时(回溯时),需要把子结果中的在该层添加的(最后添加的)删掉再返回上一层。
public class Solution {
/*
* @param s: A string
* @return: A list of lists of string
*/
public List<List<String>> partition(String s) {
// write your code here
List<List<String>> res=new ArrayList<>();
if(s==null||s.length()==0) return res;
List<String> partion=new ArrayList<>();
helper(s,0,partion,res);
return res;
}
private void helper(String s,int start,List<String> partion,List<List<String>> res){
if(start==s.length()) {
res.add(new ArrayList<>(partion));
return;
}
for(int i=start;i<s.length();i++){
String s1=s.substring(start,i+1); //前半段
if(!isPalindrome(s1)){
continue;
}
partion.add(s1);
helper(s,i+1,partion,res); //后半段
partion.remove(partion.size()-1); //return后执行,返回上一层(回溯),所以要把在改层加入partion的去除掉
}
}
private boolean isPalindrome(String s){ //判断是否是回文串
int i=0,j=s.length()-1;
while(i<j){
if(s.charAt(i)!=s.charAt(j)){
return false;
}
i++;
j--;
}
return true;
}
}
108. 切割回文串II
描述
给定一个字符串s,将s分割成一些子串,使每个子串都是回文。
返回s符合要求的的最少分割次数。
样例
比如,给出字符串s = "aab",
返回 1, 因为进行一次分割可以将字符串s分割成["aa","b"]这样两个回文子串
分析:本题采用动态规划,首先构建出二维数组isPalindrome,isPalindrome[i][j]表示是下标从i到下标为j之间构成的字符串是否是回文串。定义数组int[] f=new int[s.length()+1]表示前i个字母,最少切割几次可以切割为都是回文串。i从1开始到s.length(),然后j从0开始到i-1结束,如果isPalindrome[j][i-1]是回文串,即s[j]-s[i-1]之间是回文串,则最少只需要1次切割(对半切割)即可分成两个回文串,则前i个字母所需要的最小切割次数为f[i]和前j个字母所需最小切割次数f[j]+1之间的较小值。所以f[i]=min(f[i],f[j]+1).
public class Solution {
/**
* @param s: A string
* @return: An integer
*/
public int minCut(String s) {
// write your code here
if(s==null||s.length()==0) return 0;
boolean[][] IsPalindrome=getIsPalindrome(s);
int[] f=new int[s.length()+1]; //f[i]表示前i个字母,最少切割几次可以切割为都是回文串
for(int i=0;i<=s.length();i++) //初始化,切割成一个个的字母,如ab,切1次为a,b
f[i]=i-1;
for(int i=1;i<=s.length();i++){
for(int j=0;j<i;j++){
if(IsPalindrome[j][i-1]){ //如果IsPalindrome[j][i-1]是回文串,即s[j]-s[i-1]之间是回文串,则最少只需要1次切割(对半切割)即可分成两个回文串
if(f[i]>f[j]+1){
f[i]=f[j]+1;
}
}
}
}
return f[s.length()];
}
//isPalindrome[i][j]表示是下标从i到下标为j之间构成的字符串是否是回文串
private boolean[][] getIsPalindrome(String s){
boolean[][] isPalindrome=new boolean[s.length()][s.length()];
for(int i=0;i<s.length();i++){
isPalindrome[i][i]=true;
}
for(int i=0;i<s.length()-1;i++){
if(s.charAt(i)==s.charAt(i+1))
isPalindrome[i][i+1]=true;
}
for(int length=2;length<s.length();length++){
for(int start=0;start+length<s.length();start++){
isPalindrome[start][start+length]=isPalindrome[start+1][start+length-1] && s.charAt(start)==s.charAt(start+length);
}
}
return isPalindrome;
}
private boolean isPalindrome(String s){
int i=0,j=s.length()-1;
while(i<j){
if(s.charAt(i)!=s.charAt(j)){
return false;
}
i++;
j--;
}
return true;
}
}