Partition Labels
Problem
Cut a string into as many pieces as possible, so that each letter appears in at most one piece. Print the lengths of the pieces, in order, separated by spaces. For ababcbacadefegdehijhklij the answer is 9 7 8.
Constraints
- 1 <= length <= 500
- lowercase letters
Examples
Input
ababcbacadefegdehijhklij
Output
9 7 8
Solutions
A piece must contain every occurrence of its letters. Growing the end to the last position of each letter and cutting when the index reaches the end gives the smallest possible pieces, in one pass.
/*
* Problem : Cut into the most pieces.
* Input : One string.
* Output : The piece lengths.
* Approach: Last occurrence greedy
* Time : O(n)
* Space : O(1)
* Java : 8 or newer.
*/
import java.util.Scanner;
import java.util.Arrays;
import java.util.stream.Collectors;
public class Main {
// This method solves the task. It receives the input and returns the answer.
static int[] solve(String s) {
// Step 1: Remember the last position of every letter.
int[] last = new int[128];
for (int i = 0; i < s.length(); i++) {
last[s.charAt(i)] = i;
}
java.util.List<Integer> sizes = new java.util.ArrayList<Integer>();
int start = 0;
int end = 0;
for (int i = 0; i < s.length(); i++) {
// Step 2: The piece must reach the last position of every letter that it contains.
end = Math.max(end, last[s.charAt(i)]);
// Step 3: When we reach that end, no letter of this piece appears later. Cut here.
if (i == end) {
sizes.add(i - start + 1);
start = i + 1;
}
}
int[] out = new int[sizes.size()];
for (int i = 0; i < out.length; i++) {
out[i] = sizes.get(i);
}
return out;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s = scanner.hasNextLine() ? scanner.nextLine() : "";
System.out.println(Arrays.stream(solve(s)).mapToObj(String::valueOf).collect(Collectors.joining(" ")));
}
}
Hints (1)
- Why is a cut safe when i equals end?