LeetCode #763 Medium

Partition Labels

Partition Labels: split a string into the most parts so each letter appears in at most one part.

Constraints
  • 1 <= s.length <= 500
  • s consists of lowercase English letters.
stringgreedyhash-table
Open on LeetCode ↗
02

Intuition

Partition labels splits a string into as many pieces as possible so that each letter appears in only one piece. The instinct to cut whenever the character changes fails immediately, because a character can reappear far to the right — and if it does, both occurrences must land in the same part. That gives the governing constraint: - Once a partition contains a character, it must extend at least as far as that character's final occurrence in the whole string. So the last occurrence of every character is exactly the information needed, and one preliminary pass collects it. Then scan again, maintaining the boundary the current partition is obliged to reach. Each character encountered may push that boundary further right — never left, since the boundary is a maximum. When the scan position finally equals the boundary, every character seen in this segment has been fully consumed, and cutting here is safe. Cutting at the earliest safe position is what maximises the number of parts. Extending any further would merge two independent segments and produce fewer pieces, while cutting earlier would split a character across two parts and be invalid. The earliest safe cut is therefore both legal and optimal, which is why the greedy rule needs no backtracking.

How to spot this pattern

If each value must belong to only one segment, determine every value's full occurrence span. A greedy sweep can close a segment when all spans opened inside it have ended.

03

Approach

Try it first

Before reading on: price up what enumerating every case costs here, then ask why the locally best choice is safe to commit to and never revisit. Aim for O(n) time and O(1) space.

1

Record each character's last index

Scan the string once, overwriting last[char] with the current index each time. This single pass supplies the only lookup the algorithm needs — how far a partition must stretch once it contains a given character.

2

Track the boundary the segment must reach

During the second scan, keep an end value. For every character, set end = max(end, last[char]). New characters inside the segment can only push it further right, never pull it back.

3

Cut when the index reaches the boundary

When the scan position equals end, every character in this segment has its final occurrence at or before here. Record the segment length and start the next one at the following index.

4

Understand why the earliest cut is optimal

Cutting sooner would split a character across two parts and be invalid; cutting later would merge two independent segments and yield fewer pieces. The earliest safe cut is therefore both legal and maximal — no backtracking is ever needed.

5

Return lengths, not the substrings

The problem asks for the size of each part, so append end - start + 1 and set start = end + 1. Building the actual substrings is extra work the answer does not require.

6

Cost of the two passes

Two linear scans over the string give O(n) time, and the last-occurrence map is bounded by the alphabet size, so space is O(1) for lowercase input — 26 entries regardless of string length.

04

Solution & live demo

▶1class Solution:
▶2 def partitionLabels(self, s:
▶3 str) -> List[int]:
▶4 last = {char: i for i, char in enumerate(s)}
▶5 sizes = []
▶6 start = 0
▶7 end = 0
▶8 for i, char in enumerate(s):
▶9 end = max(end, last[char])
▶10 if i == end:
▶11 sizes.append(end - start + 1)
▶12 start = end + 1
▶13 return sizes
05

Common pitfalls

Cutting at the current character's last index only

✗ Wrong
end = last[char]
✓ Right
end = max(end, last[char])

An earlier character in the partition may require a later boundary.

Computing the wrong segment length

✗ Wrong
sizes.append(end - start)
✓ Right
sizes.append(end - start + 1)

Both boundary indices belong to the partition.

Starting the next segment at the boundary

✗ Wrong
start = end
✓ Right
start = end + 1

The boundary character was already included in the completed segment.

06

Edge cases

All characters are distinct

Every last occurrence equals its current index, producing one-character partitions.

One character fills the string

Its last occurrence extends the first partition to the final index.

Nested occurrence ranges

The running maximum absorbs every inner range before a cut is made.

07

Complexity

Time
O(n)
Space
O(1)
The lowercase alphabet bounds the last-occurrence table to constant size.