AlgoMaster Logo

Partition Labels

mediumFrequencyUpdated September 21, 2026

Understanding the Problem

We need to split a string into the maximum number of parts where no letter appears in more than one part. Consider what that constraint means: if the letter 'a' appears at positions 0, 3, and 8, then all three of those positions must belong to the same partition. That partition must stretch at least from index 0 to index 8.

This leads to the core idea. Once we start a partition and encounter a character, we must extend the partition at least to the last occurrence of that character. Extending it may pull in new characters whose last occurrences push the boundary further out. The partition ends only when we reach a position where every character encountered so far has its last occurrence at or before the current position.

Key Constraints:

  • 1 <= s.length <= 500 → An O(n^2) scan stays under 250,000 operations here, so even a brute-force approach runs fast. The greedy O(n) solution below is preferred because it removes the repeated work.
  • s consists of lowercase English letters → Only 26 possible characters, so a last-occurrence array of size 26 uses O(1) space.

Approach 1: Brute Force (Expand Partition Boundaries)

Intuition

Start a partition at index 0. Find where the first character last appears in the string; that index is the minimum end boundary. Scan every character between the start and that boundary. Each one may have a last occurrence further out, so extend the boundary whenever that happens. Once the scan reaches the boundary without extending it further, the partition is complete. Record its size and start the next partition.

This follows the same logic as the optimal solution, except it recomputes each last occurrence with a fresh scan instead of precomputing them once. That repeated work is what the next approach removes.

Algorithm

  1. Start with partitionStart = 0.
  2. Set end to the last occurrence of s[partitionStart] (found by scanning the string from the right).
  3. For each index i from partitionStart to end, find the last occurrence of s[i]. If it is beyond end, update end.
  4. When i reaches end, the partition is complete. Add end - partitionStart + 1 to the result.
  5. Set partitionStart = end + 1 and repeat until the string is fully partitioned.

Visualization and Code

Loading animation...

The last occurrence of each character never changes during the run, yet this approach recomputes it on every scan. Precomputing all 26 last occurrences once turns the repeated inner search into a single array lookup.

Approach 2: Greedy with Last Occurrence Map (Optimal)

Intuition

There are only 26 lowercase letters, so we can record where each character last appears in a single O(n) pass. With that map in hand, the partitioning becomes one greedy left-to-right scan.

Walk through the string maintaining the current partition's end boundary. For each character at position i, update end = max(end, lastOccurrence[char]). When i == end, every character seen so far in this partition has its last occurrence at or before position i, so no character from this partition appears later in the string and the cut is safe.

Algorithm

  1. Create an array last of size 26, where last[c] stores the last index of character c in the string.
  2. Fill last by scanning the string once from left to right.
  3. Initialize partitionStart = 0 and end = 0.
  4. Iterate through the string with index i:
    • Update end = max(end, last[s[i]]).
    • If i == end, the current partition is complete. Add end - partitionStart + 1 to the result. Set partitionStart = i + 1.
  5. Return the result list.

Visualization and Code

Loading animation...