题目描述:
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.
public class Solution {
Map<String,Integer> map=new HashMap<String,Integer>();
public int minCut(String s) {
int min=Integer.MAX_VALUE;
if(isPalindrome(s))
return 0;
for(int i=0;i<s.length()-1;i++){
String substr=s.substring(0,i+1);
if(set.contains(substr)){
int cutnum=minCut(s.substring(i+1));
min=cutnum+1<min?cutnum+1:min;
}else{
if(isPalindrome(substr)){
set.add(substr);
int cutnum=minCut(s.substring(i+1));
min=cutnum+1<min?cutnum+1:min;
}else{
int cutnum=minCut(s.substring(0,i+1))+minCut(s.substring(i+1,s.length()))+1;
min=cutnum+1<min?cutnum+1:min;
}
}
}
return min;
}
}
后来我加了备忘录,然后想想这里每次调用substring函数很浪费时间,于是我换成了char[],速度快了很多,但还是超时了,WTF!
public class Solution {
Map<String,Integer> map=new HashMap<String,Integer>();
public int minCut(String s) {
return getMinCut(s.toCharArray(), 0,s.length()-1);
}
public int getMinCut(char[] chars,int left,int right){
String str=new String(chars, left, chars.length-left);
if(map.containsKey(str))
return map.get(str);
if(isPalindrome(chars,left,right))
return 0;
int min=Integer.MAX_VALUE;
for(int i=left;i<right;i++){
String substr=new String(chars, left, i-left+1);
if(map.containsKey(substr)){
int leftCut=map.get(substr);
int rightCut=getMinCut(chars,i+1,right);
min=leftCut+rightCut+1<min?leftCut+rightCut+1:min;
}else{
if(isPalindrome(chars,left,i)){
map.put(substr,0);
int rightCut=getMinCut(chars,i+1,right);
min=rightCut+1<min?rightCut+1:min;
}else{
int leftCut=getMinCut(chars,left,i);//这个地方写成了i+1
int rightCut=getMinCut(chars,i+1,right);
min=leftCut+rightCut+1<min?leftCut+rightCut+1:min;
}
}
}
map.put(str, min);
return min;
}
private boolean isPalindrome(char[] chars,int left,int right){
while(left<right){
if(chars[left]==chars[right]){
left++;right--;
}else{
return false;
}
}
return true;
}
}
这个题正确的自上而下的dfp算法:
这里在判断是否是回文数的时候直接在panMap中查找。
public class Solution {
int[][] panMap;
int[] map;
public int minCut(String s) {
panMap = new int[s.length()][s.length()];
map = new int[s.length() + 1];
Arrays.fill(map, Integer.MAX_VALUE);
map[s.length()] = 0;
return minCut(s, 0) - 1;
}
private int minCut(String s, int start) {
if (map[start] != Integer.MAX_VALUE) return map[start];
for (int i = start; i < s.length(); i++) {
//这里当start==i时肯定会执行
if (isPan(s, start, i)) {
map[start] = Math.min(map[start], 1 + minCut(s, i + 1));
}
}
return map[start];
}
private boolean isPan(String s, int start, int end) {
if (start == end) return true;
if (end == start - 1 && s.charAt(start) == s.charAt(end)) return true;
if (panMap[start][end] != 0) return panMap[start][end] == 1 ? true : false;
if (s.charAt(start) == s.charAt(end)) {
panMap[start][end] = isPan(s, start + 1, end - 1) ? 1 : -1;
}
return panMap[start][end] == 1 ? true : false;
}
}
自下而上的dp算法:
This can be solved by two points:
cut[i]
is the minimum ofcut[j - 1] + 1 (j <= i)
, if[j, i]
is palindrome.- If
[j, i]
is palindrome,[j + 1, i - 1]
is palindrome, andc[j] == c[i]
.
public class Solution {
public int minCut(String s) {
char[] c = s.toCharArray();
int n = c.length;
int[] cut = new int[n];
boolean[][] pal = new boolean[n][n];
for(int i = 0; i < n; i++) {
//这里给min赋初始值
int min = i;
for(int j = 0; j <= i; j++) {
if(c[j] == c[i] && (j + 1 > i - 1 || pal[j + 1][i - 1])) {
pal[j][i] = true;
min = j == 0 ? 0 : Math.min(min, cut[j - 1] + 1);
}
}
cut[i] = min;
}
return cut[n - 1];
}
}