Palindrome Partitioning: Minimum Cuts
Problem
Cut a string into pieces so that every piece is a palindrome (reads the same backwards). Print the smallest number of cuts needed. A string that is already a palindrome needs 0 cuts.
Constraints
- 1 <= length <= 2000
Examples
Input
aab
Output
1
Input
abcd
Output
3
Solutions
A table tells in O(1) whether any piece is a palindrome. Then a second table finds the best cut count for each prefix by trying every last piece. Total time and memory are O(n^2).
/*
* Problem : Fewest cuts.
* Input : One string.
* Output : The number of cuts.
* Approach: Palindrome table + DP
* Time : O(n^2)
* Space : O(n^2)
* Java : 8 or newer.
*/
import java.util.Scanner;
public class Main {
// This method solves the task. It receives the input and returns the answer.
static long solve(String s) {
int n = s.length();
// Step 1: pal[i][j] says whether the piece from i to j is a palindrome. A piece is one if the ends match and the inside is one.
boolean[][] pal = new boolean[n][n];
for (int i = n - 1; i >= 0; i--) {
for (int j = i; j < n; j++) {
pal[i][j] = s.charAt(i) == s.charAt(j) && (j - i < 2 || pal[i + 1][j - 1]);
}
}
// Step 2: cuts[j] is the minimum cuts for the first j + 1 letters.
long[] cuts = new long[n];
for (int j = 0; j < n; j++) {
if (pal[0][j]) {
cuts[j] = 0;
continue;
}
// Step 3: Try the last piece from i to j. It adds one cut after the best answer for the letters before it.
cuts[j] = j;
for (int i = 1; i <= j; i++) {
if (pal[i][j]) {
cuts[j] = Math.min(cuts[j], cuts[i - 1] + 1);
}
}
}
return cuts[n - 1];
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s = scanner.hasNextLine() ? scanner.nextLine() : "";
System.out.println(solve(s));
}
}
Hints (2)
- Why is the palindrome table filled from the end?
- What is the largest answer for a string of n letters?