Chapter 7: Foundational Problem-Solving Patterns
7.06Beginner5 topics18 min2 interactive animations

Sorting as a pattern

Sorting first is often the cheapest way to make a problem easy. Once data is ordered, duplicates sit together, overlaps are adjacent and events happen in time order, so a single scan finishes the job.

Learning goals

  • Recognise problems that become a linear scan after an O(n log n) sort
  • Group equal or equivalent items by sorting on a key
  • Merge intervals and count overlapping events with a sweep
  • Write correct custom sort keys and tie-breakers

Prerequisites

Sorting and ComparatorsTwo pointersFrequency maps

Checking a stack of receipts for duplicates is hard when they are shuffled and easy once they are sorted by date: duplicates end up next to each other.

7.06.1

Sort then scan

Many problems that look like they need comparing all pairs become a single pass once the data is sorted. The sort costs O(n log n) and the scan O(n), which is usually acceptable, and it uses no extra hash structures.

Examples: find any duplicate (compare neighbours), the minimum difference between two elements (it is between neighbours), and 3Sum (sort, then two pointers for each first element).

Java
1static int minimumDifference(int[] arr) {
2 int[] a = arr.clone();
3 Arrays.sort(a);
4 int best = Integer.MAX_VALUE;
5 for (int i = 1; i < a.length; i++) {
6 best = Math.min(best, a[i] - a[i - 1]); // the closest pair is always adjacent after sorting
7 }
8 return best;
9}

Worst

O(n log n)

Space

O(1) to O(n)

7.06.2

Group equals

To group items that are “the same” under some definition, sort them by a key that captures that definition, or map each item to a canonical key. Anagrams share the same sorted letters, so the sorted string is a natural key.

Sorting the whole list groups equal keys together (O(n log n)); a HashMap<key, List> groups them without sorting the list (expected O(n), plus the cost of computing each key).

Java
1static Collection<List<String>> groupAnagrams(String[] words) {
2 Map<String, List<String>> groups = new HashMap<>();
3 for (String w : words) {
4 char[] key = w.toCharArray();
5 Arrays.sort(key); // canonical form: letters in order
6 groups.computeIfAbsent(new String(key), k -> new ArrayList<>()).add(w);
7 }
8 return groups.values();
9}
7.06.3

Meeting intervals

Sort intervals by start. Then two intervals overlap only if one starts before the previous one ends, so a single scan can merge them: extend the last merged interval or start a new one.

Enter your own start, end pairs in the animation. The top lane shows the intervals in sorted order; the bottom lane shows the merged result growing.

Worst

O(n log n)

Space

O(n)

Merge overlapping intervals (sort by start, then scan)

Interactive · edit the input

Your input

Try

input

[8, 10]
[1, 3]
[15, 18]
[2, 6]
[9, 12]
0123456789101112131415161718
Setup

In input order, overlaps can be far apart. Sorting by start puts every overlap next to its neighbour.

Step 1 / 13
Java
1public static List<int[]> merge(int[][] intervals) {
2 Arrays.sort(intervals, Comparator.comparingInt(a -> a[0])); // sort by start
3 List<int[]> merged = new ArrayList<>();
4 for (int[] cur : intervals) {
5 int[] last = merged.isEmpty() ? null : merged.get(merged.size() - 1);
6 if (last != null && cur[0] <= last[1]) {
7 last[1] = Math.max(last[1], cur[1]); // overlap: extend
8 } else {
9 merged.add(cur); // gap: start a new interval
10 }
11 }
12 return merged;
13}

Live state

0 comparisons

intervals

5

No condition evaluated on this step
Execution trace (dry run table)Show 13 steps
StepLineStateWhat happens
1L1intervals=5In input order, overlaps can be far apart. Sorting by start puts every overlap next to its neighbour.
2L2intervals=5Sorted by start: O(n log n). Now one left-to-right scan is enough.
3L6start=1 end=3 last end=noneNothing merged yet: this interval starts the list.
4L9merged=1Append [1, 3] as a new merged interval.
5L6start=2 end=6 last end=3[2, 6] starts before the last merged interval ends, so they overlap.
6L7last end=6Extend the last interval: end = max(3, 6) = 6.
7L6start=8 end=10 last end=6[8, 10] starts after 6: there is a gap.
8L9merged=2Append [8, 10] as a new merged interval.
9L6start=9 end=12 last end=10[9, 12] starts before the last merged interval ends, so they overlap.
10L7last end=12Extend the last interval: end = max(10, 12) = 12.
11L6start=15 end=18 last end=12[15, 18] starts after 12: there is a gap.
12L9merged=3Append [15, 18] as a new merged interval.
13L12return=[1,6] [8,12] [15,18]5 intervals became 3. O(n log n) for the sort plus O(n) for the scan.
7.06.4

Sweep sorted events

A sweep line moves through time and processes events in sorted order: each start adds one to a running count, each end subtracts one. The maximum running count is the maximum number of simultaneous events, which is the number of meeting rooms needed.

Sorting starts and ends separately and walking them with two pointers avoids building event objects. With half-open intervals [start, end), an end at time t frees its room before a start at the same t takes one, which is why the loop uses <=.

Worst

O(n log n)

Space

O(n)

Minimum meeting rooms (sweep sorted events)

Interactive · edit the input

Your input

Try
t=0

meetings

[0, 30]
[5, 10]
[10, 25]
[15, 20]
[22, 28]
0123456789101112131415161718192021222324252627282930

starts (sorted)

0
5
10
15
22

ends (sorted)

10
20
25
28
30
Setup

Only the times matter, not which meeting is which. Sort starts and ends separately and sweep left to right.

Step 1 / 9
Java
1public static int minRooms(int[][] meetings) { // [start, end), end is exclusive
2 int n = meetings.length;
3 int[] starts = new int[n], ends = new int[n];
4 for (int i = 0; i < n; i++) { starts[i] = meetings[i][0]; ends[i] = meetings[i][1]; }
5 Arrays.sort(starts);
6 Arrays.sort(ends);
7 int rooms = 0, best = 0, e = 0;
8 for (int s = 0; s < n; s++) {
9 while (ends[e] <= starts[s]) { e++; rooms--; } // meetings that ended free a room
10 rooms++;
11 best = Math.max(best, rooms);
12 }
13 return best;
14}

Live state

0 events

rooms

0

best

0

No condition evaluated on this step
Execution trace (dry run table)Show 9 steps
StepLineStateWhat happens
1L5rooms=0 best=0Only the times matter, not which meeting is which. Sort starts and ends separately and sweep left to right.
2L11time=0 rooms=1 best=1A meeting starts at 0: 1 room in use. Peak so far 1.
3L11time=5 rooms=2 best=2A meeting starts at 5: 2 rooms in use. Peak so far 2.
4L9time=10 rooms=1 best=2A meeting ended at 10 ≤ 10: its room is free again.
5L11time=10 rooms=2 best=2A meeting starts at 10: 2 rooms in use. Peak so far 2.
6L11time=15 rooms=3 best=3A meeting starts at 15: 3 rooms in use. Peak so far 3.
7L9time=22 rooms=2 best=3A meeting ended at 20 ≤ 22: its room is free again.
8L11time=22 rooms=3 best=3A meeting starts at 22: 3 rooms in use. Peak so far 3.
9L13return=33 rooms needed: the maximum number of meetings overlapping at any moment. O(n log n).
7.06.5

Sorting with custom key

Real problems sort by derived keys: by end time for interval scheduling, by frequency then value, by distance from a point. Build the comparator from Comparator.comparing and chain tie-breakers with thenComparing.

Sorting by end time is the key step in the greedy “maximum non-overlapping intervals” algorithm: always keep the interval that finishes first. Sorting by start time would be wrong for that problem.

Java
1// most frequent first, ties broken by smaller value
2Integer[] boxed = Arrays.stream(nums).boxed().toArray(Integer[]::new);
3Map<Integer, Long> freq = Arrays.stream(nums).boxed()
4 .collect(Collectors.groupingBy(x -> x, Collectors.counting()));
5Arrays.sort(boxed, Comparator.<Integer, Long>comparing(freq::get).reversed()
6 .thenComparing(Comparator.naturalOrder()));
7
8// interval scheduling: sort by end time
9Arrays.sort(intervals, Comparator.comparingInt(iv -> iv[1]));

Practice ladder

Now try it yourself

Easy

  • Contains duplicate (sort version)
  • Minimum absolute difference
  • Meeting rooms (can attend all?)

Medium

  • Merge intervals
  • Meeting rooms II
  • Group anagrams
  • Non-overlapping intervals

Advanced

  • Insert interval
  • Employee free time
  • Minimum number of arrows to burst balloons

Key takeaways

  • An O(n log n) sort often turns a quadratic pair search into a linear scan.
  • Sort intervals by start to merge them; sweep sorted starts and ends to count overlaps.
  • Choose the sort key deliberately and break ties explicitly with thenComparing.