LeetCode ยท #763

Partition Labels Solution

Partition a string into as many parts as possible so each letter appears in at most one part. Return the list of part sizes.

01
Section One ยท Problem

Problem Statement

๐Ÿท๏ธ

Difficulty

Medium

๐Ÿ”—

LeetCode

Problem #763

๐Ÿ—๏ธ

Pattern

Greedy โ€” last occurrence + merge

Given a string s, partition it into as many parts as possible so that each letter appears in at most one part. Return a list of integers representing the size of each part.

Example
Input: s = "ababcbacadefegdehijhklij" Output: [9, 7, 8] // "ababcbaca" (9), "defegde" (7), "hijhklij" (8)
Constraints
โ€ข 1 โ‰ค s.length โ‰ค 500 โ€ข s consists of lowercase English letters
02
Section Two ยท Approach 1

Brute Force โ€” O(nยฒ)

For each partition start, scan forward to find the last occurrence of each character encountered. Extend the partition until all characters are contained.

Problem: Rescanning for last occurrences is O(n) per partition. Pre-compute last occurrences in O(n), then do a single greedy pass.
Java โ€” Pre-scan but O(nยฒ) partition
class Solution { public List<Integer> partitionLabels(String s) { List<Integer> res = new ArrayList<>(); int start = 0; while (start < s.length()) { int end = s.lastIndexOf(s.charAt(start)); // O(n) for (int k = start; k < end; k++) end = Math.max(end, s.lastIndexOf(s.charAt(k))); // O(n) res.add(end - start + 1); start = end + 1; } return res; } }
Python โ€” Brute
class Solution: def partitionLabels(self, s: str) -> list[int]: res, start = [], 0 while start < len(s): end = s.rindex(s[start]) k = start while k < end: end = max(end, s.rindex(s[k])) k += 1 res.append(end - start + 1) start = end + 1 return res
03
Section Three ยท Approach 2

Greedy โ€” O(n) time, O(1) space

Pre-compute last[c] = last index of each character. Then scan left to right, extending each partition's end to max(end, last[s[i]]). When i == end, the partition is complete.

๐Ÿ’ก Mental model: Imagine each letter is a rubber band stretched from its first occurrence to its last. You start at the left edge and walk right. Each letter you encounter forces you to extend your current partition to at least the end of its rubber band. When you reach the farthest rubber band end, cut โ€” that's a partition boundary. All rubber bands within the partition are fully contained.
Algorithm
  • Build last[26]: last occurrence of each letter.
  • start = 0, end = 0. For each i:
  • end = max(end, last[s[i]]). If i == end: add end - start + 1 to result, start = i + 1.
๐ŸŽฏ When to recognize this pattern: "Partition string/array into segments where no element appears in multiple segments." The signal: constraint-based partitioning. Pre-compute ranges, then merge overlapping ranges greedily โ€” similar to interval merging (LC 56).
04
Section Four ยท Trace

Visual Walkthrough

Trace for s = "ababcbacadefegdehijhklij".

Partition Labels โ€” Last Occurrence + Greedy Sweep
last[a]=8, last[b]=5, last[c]=7, last[d]=14, last[e]=15, ... i=0 'a': end=max(0,8)=8. i=1 'b': end=max(8,5)=8. ... i=8 'a': i==end=8 โ†’ partition size 9. Part 1: "ababcbaca" (indices 0-8, size 9) i=9 'd': end=14. i=10 'e': end=15. ... i=15 'e': i==end=15 โ†’ partition size 7. Part 2: "defegde" (indices 9-15, size 7) i=16 'h': end=19. i=17 'i': end=22. ... i=22 'j': i==end=22 โ†’ partition size 8. Part 3: "hijhklij" (indices 16-23, size 8)
05
Section Five ยท Implementation

Code โ€” Java & Python

Java โ€” Greedy
import java.util.*; class Solution { public List<Integer> partitionLabels(String s) { int[] last = new int[26]; for (int i = 0; i < s.length(); i++) last[s.charAt(i) - 'a'] = i; List<Integer> res = new ArrayList<>(); int start = 0, end = 0; for (int i = 0; i < s.length(); i++) { end = Math.max(end, last[s.charAt(i) - 'a']); if (i == end) { res.add(end - start + 1); start = i + 1; } } return res; } }
Python โ€” Greedy
class Solution: def partitionLabels(self, s: str) -> list[int]: last = {c: i for i, c in enumerate(s)} res, start, end = [], 0, 0 for i, c in enumerate(s): end = max(end, last[c]) if i == end: res.append(end - start + 1) start = i + 1 return res
06
Section Six ยท Analysis

Complexity Analysis

ApproachTimeSpaceTrade-off
Brute forceO(nยฒ)O(1)Rescan for each partition
Greedy โ† optimalO(n)O(1)26-char array is constant space; two passes
07
Section Seven ยท Edge Cases

Edge Cases & Pitfalls

CaseInputWhy It Matters
Single char"a"One partition of size 1.
All unique"abcde"Each char appears once โ†’ five partitions of size 1: [1,1,1,1,1].
All same"aaaa"One partition of size 4.
Nested ranges"abacd"'a' spans 0-2, 'b' at 1. Partition 1: "aba" (3). Then "c" (1), "d" (1).
โš  Common Mistake: Using the first occurrence instead of the last occurrence. First occurrence tells you where a character starts, but the partition must extend to where it ends. Always pre-compute last[c] and extend to the farthest last occurrence seen so far.

โ† Back to Greedy problems