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.
Example:
Input: "aab" Output: 1 Explanation: The palindrome partitioning ["aa","b"] could be produced using 1 cut.
题目理解:给定一个字符串str,将这个字符串切分成几个子串,使得每个子串都是回文,问最少切分几次
解题思路:动态规划;动态规划的实质是记录之前步骤的信息用于当前。我们用dp[i]表示0~i的子串最少切分次数。考虑递推公式,用str[i]表示str的下标为i的字符,如果str[j] = str[i] && i < j && str的i+1~j-1子串是回文,即str的i~j子串是回文,那么在str的0~i子串切分dp[i-1]+1次一定可以满足要求;因此,考虑到我们需要判断str的i+1~j-1子串是不是子串,因此我们使用一个字典,保存以j为终点的全部回文子串的起点,因为我们从j=0开始计算,因此,计算j时,以j-1为终点的全部回文子串起点已经都记录了,代码如下:
public int minCut(String s) {
int len = s.length();
Map<Integer, Set<Integer>> map = new HashMap<Integer, Set<Integer>>();
int record[] = new int[len];
Arrays.fill(record, len - 1);
record[0] = 0;
char[] chs = s.toCharArray();
for(int j = 0; j < len; j++){
map.put(j, new HashSet<Integer>());
map.get(j).add(j);
if(j != 0)
record[j] = record[j - 1] + 1;
for(int i = 0; i < j; i++){
if(chs[i] == chs[j] && (i + 1 == j || map.get(j - 1).contains(i + 1))){
map.get(j).add(i);
if(i != 0)
record[j] = Math.min(record[j], record[i - 1] + 1);
else
record[j] = 0;
}
}
//System.out.println(j + " " + map.get(j).toString());
}
return record[len - 1];
}
进一步思考,在计算dp[j]时,其实我们并不需要0~j-1之间全部回文子串信息,我们需要的只是以j-1为终点的回文子串信息,因此考虑用两个bool数组记录回文子串信息
public int minCut(String s) {
int len = s.length();
boolean[] cur = new boolean[len], next;
int record[] = new int[len];
Arrays.fill(record, len - 1);
record[0] = 0;
char[] chs = s.toCharArray();
for(int j = 0; j < len; j++){
next = new boolean[len];
next[j] = true;
if(j != 0)
record[j] = record[j - 1] + 1;
for(int i = 0; i < j; i++){
if(chs[i] == chs[j] && (i + 1 == j || cur[i + 1])){
next[i] = true;;
if(i != 0)
record[j] = Math.min(record[j], record[i - 1] + 1);
else
record[j] = 0;
}
}
cur = next;
}
return record[len - 1];
}