[LintCode]Palindrome Partitioning II
这是一道比较复杂的动态规矩题,但不难。复杂是因为它实际上用了两次动态规划,而第二次的目的是降低时间复杂度。不难是因为第一次动态规划其实比较常规。
这道题我做了四次,见下,前两次是错的,第三次是对的,但是只用了一次动态规划,时间复杂度是O(n^3),第四次也是对的,用了两次动态规划,时间复杂度降到了O(n^2)。
Version 1
public class Solution {
/**
* @param s a string
* @return an integer
*/
public int minCut(String s) {
// 2015-05-16
if (s == null || s.length() == 0) {
return 0;
}
int n = s.length();
int[] minimum = new int[n];
minimum[0] = 0;
for (int i = 1; i < n; i++) {
for (int j = 0; j <= i; j++) {
if (isPalindrome(s, j, i)) {
minimum[i] = (j == 0 ? 0 : minimum[j - 1] + 1);
break;
}
}
}
return minimum[n - 1];
}
private boolean isPalindrome(String s, int start, int end) {
if (s == null || s.length() == 0) {
return false;
}
if (start > end) {
return false;
}
while (start < end) {
if (s.charAt(start) != s.charAt(end)) {
return false;
}
start++;
end--;
}
return true;
}
};
Version 2
public class Solution {
/**
* @param s a string
* @return an integer
*/
public int minCut(String s) {
// 2015-05-16
if (s == null || s.length() == 0) {
return 0;
}
int n = s.length();
int[][] cut = new int[n][n];
for (int i = 0; i < n; i++) {
cut[i][i] = 0;
}
for (int k = 1; k < n; k++) {
for (int i = 0; i + k < n; i++) {
int j = i + k;
if (isPalindrome(s, i, j)) {
cut[i][j] = 0;
} else {
cut[i][j] = Math.min(cut[i + 1][j], cut[i][j - 1]) + 1;
} // if
} // for
} // for
return cut[0][n - 1];
}
private boolean isPalindrome(String s, int start, int end) {
if (s == null || s.length() == 0) {
return false;
}
if (start > end) {
return false;
}
while (start < end) {
if (s.charAt(start) != s.charAt(end)) {
return false;
}
start++;
end--;
}
return true;
}
};
Version 3
public class Solution {
/**
* @param s a string
* @return an integer
*/
public int minCut(String s) {
// 2015-05-16 O(n^3)
if (s == null || s.length() == 0) {
return 0;
}
int n = s.length();
int[] cut = new int[n];
cut[0] = 0;
for (int i = 1; i < n; i++) {
cut[i] = Integer.MAX_VALUE;
for (int j = 0; j <= i; j++) {
if (isPalindrome(s, j, i)) {
cut[i] = (j == 0 ? 0 : Math.min(cut[i], cut[j - 1] + 1));
} // if
}// for
}// for
return cut[n - 1];
}
// O(n)
private boolean isPalindrome(String s, int start, int end) {
if (s == null || s.length() == 0) {
return false;
}
if (start > end) {
return false;
}
while (start < end) {
if (s.charAt(start) != s.charAt(end)) {
return false;
}
start++;
end--;
}
return true;
}
};
Version 4
public class Solution {
/**
* @param s a string
* @return an integer
*/
public int minCut(String s) {
// 2015-05-16 O(n^2)
if (s == null || s.length() == 0) {
return 0;
}
int n = s.length();
int[] cut = new int[n];
boolean[][] palindrome = getPalindrome(s);
cut[0] = 0;
for (int i = 1; i < n; i++) {
cut[i] = Integer.MAX_VALUE;
for (int j = 0; j <= i; j++) {
if (palindrome[j][i]) {
cut[i] = (j == 0 ? 0 : Math.min(cut[i], cut[j - 1] + 1));
} // if
}// for
}// for
return cut[n - 1];
}
// O(n)
private boolean isPalindrome(String s, int start, int end) {
if (s == null || s.length() == 0) {
return false;
}
if (start > end) {
return false;
}
while (start < end) {
if (s.charAt(start) != s.charAt(end)) {
return false;
}
start++;
end--;
}
return true;
}
// O(n^2) 第二次dp
private boolean[][] getPalindrome(String s) {
if (s == null || s.length() == 0) {
return null;
}
int n = s.length();
boolean[][] ret = new boolean[n][n];
for (int i = 0; i < n; i++) {
ret[i][i] = true;
}
for (int i = 0; i < n - 1; i++) {
int j = i + 1;
ret[i][j] = isPalindrome(s, i, j);
}
for (int len = 2; len < n; len++) {
for (int i = 0; i + len < n; i++) {
int j = i + len;
ret[i][j] = (s.charAt(i) == s.charAt(j) && ret[i + 1][j - 1]);
}
}
return ret;
}
};
本文详细解析了LintCode上的Palindrome Partitioning II问题,通过四个版本的代码实现展示了从错误到正确的解题过程,并最终实现了时间复杂度为O(n^2)的解决方案。
7716

被折叠的 条评论
为什么被折叠?



