Problem Statement

Partition Labels

You are given a string s, which is just a line of letters. Your job is to cut it into as many pieces as you can, with one rule: a letter can only live in one piece. So if the letter "a" shows up three times, all three "a"s have to end up in the same piece. The answer is a list of the sizes of those pieces. The trick that makes this easy is to first find, for every letter, the last spot it appears. Then we sweep left to right and keep stretching the current piece until it covers the last spot of every letter we have seen so far. When the sweep finally catches up to that far edge, we cut. This stretch-as-needed move is called greedy, which means we make the choice that looks best right now (extend just far enough) and never look back.

mediumGreedyStringGreedyTime: O(n) · Space: O(1)

Signals to notice

partition string into parts where each character appears in at most one partmaximize partition counttrack last occurrence

Brute force first

Try all possible partition points. Each position is either a cut or not. It is a fair place to begin because it matches the surface of the question, yet it does not capture the deeper structure that makes the problem simpler.

The key insight

First pass: record each character's last occurrence. Second pass: expand the current partition to include the last occurrence of every character in it. When you reach the partition boundary, cut. Once you hold onto the right piece of information from moment to moment, the problem feels less like trial and error and more like following a shape that was there all along.

Trace it on s = "ababcbacadefegdehijhklij"

pre-pass last = {a:8, b:5, c:7, d:14, e:15, f:11, g:13, h:19, i:22, j:23, k:20, l:21}; start=0, end=0, result=[]
i=0 'a': end=max(0,8)=8; i!=end, keep going
i=5 'b': end=max(8,5)=8 (still 8); i!=end
i=8 'a': end=max(8,8)=8; i==end -> cut, result=[9], start=9
i=14 'd': end=max(15,14)=15 (e at 10 pushed end to 15); i!=end
i=15 'e': end=15; i==end -> cut, result=[9,7], start=16
i=22 'i': end=max(23,22)=23 (j,k,l already pushed end to 23); i!=end
i=23 'j': end=23; i==end -> cut, result=[9,7,8], start=24; loop ends -> return [9,7,8]

What must stay true

If character 'a' appears at positions 2 and 8, any partition containing position 2 must also contain position 8. The partition boundary is the maximum last occurrence of any character in it. When you keep that truth intact, each local choice supports the larger solution instead of fighting it.

Shape of the loop

last = { char: last_index_in_s }   // pre-pass
start = end = 0
for i, c in s:
    end = max(end, last[c])        // stretch boundary
    if i == end:                   // every char inside ends here
        emit(end - start + 1); start = i + 1

Pseudocode only — the full worked solution lives in the Solution tab.

Easy way to go wrong

Greedily cutting at the first opportunity without checking if later characters force the partition to extend. The max-last-occurrence tracking handles this. The fix is usually to return to the meaning of each move, not just the steps themselves.

Greedy Pattern