Partition Labels

medium Strings

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

Best approachTime O(n)Space O(1)

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.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * 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)
  1. Why is a cut safe when i equals end?