Suffix array nlogn creation
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
A suffix array stores the starting positions of all suffixes of a string in lexicographic order. The classic way to build one in O(n log n) time is the doubling algorithm: repeatedly sort suffixes by the first 2^k characters while reusing the ranks computed in the previous pass.
The Core Idea Behind the Doubling Method
Suppose the input string is banana. At the start, each suffix can be ranked by just its first character. After that, you sort suffixes by pairs of ranks:
- current rank of position
i - current rank of position
i + 2^k
Once those pairs are sorted, you assign new ranks and double the compared prefix length for the next round.
The important observation is that if you already know the order of prefixes of length 2^k, then the order of prefixes of length 2^(k+1) can be derived from rank pairs instead of by comparing long strings character by character.
A Runnable O(n log n) Implementation in C++
To keep the overall complexity at O(n log n), each round must sort rank pairs in linear time, usually with counting sort because the ranks are integers in the range 0 through n - 1.
For banana, the output is 5 3 1 0 4 2, which is the expected suffix array.
Why the Complexity Is O(n log n)
There are about log n rounds because the compared prefix length doubles each time. If each round uses counting sort on integer ranks, the work per round is linear in n.
That gives the total complexity:
- '
O(n)work per doubling round' - '
O(log n)rounds' - total
O(n log n)
If you replace counting sort with a comparison sort in every round, the complexity becomes O(n log^2 n). The doubling idea is still the same, but the asymptotic guarantee changes.
Reading the Data Structures
The main arrays in the algorithm each have a specific job:
- '
sastores the current order of suffix starts' - '
rankstores the equivalence class of each suffix prefix' - '
countsupports counting sort over rank values'
Once all suffixes have distinct ranks, the ordering is complete. The sentinel character "$" ensures every suffix is properly terminated and that one suffix is strictly smallest.
This representation is also useful beyond construction. A suffix array can support substring search with binary search, and it is the starting point for building the LCP array used in many string algorithms.
Common Pitfalls
A common mistake is calling a tuple-based comparison sort in each doubling round and then claiming the implementation is O(n log n). Without radix or counting sort on integer ranks, it is usually O(n log^2 n).
Another mistake is forgetting the sentinel character. Without a unique smallest terminator, cyclic shifts and true suffixes become harder to separate correctly.
Indexing bugs are also common when computing the second half of a rank pair. In cyclic-shift style implementations, the second index is wrapped with modulo arithmetic until the sentinel is removed at the end.
Finally, be clear about the difference between algorithm idea and language implementation. The doubling method supports O(n log n), but only if the per-round sorting step respects that bound.
Summary
- A suffix array stores suffix starting indices in lexicographic order.
- The doubling method sorts suffixes by rank pairs for prefixes of length
2^k. - Counting sort on integer ranks keeps each round linear.
- Using comparison sort each round changes the bound to
O(n log^2 n). - The sentinel character and careful rank updates are essential for correctness.
Related reading
- Suffix tree and Tries. What is the difference?
- Suggest an algorithm graph - possibly NP-Complete
- Suggest websites to practice C/C algorithms/puzzles
- Suggested algorithms/methods for laying out labels on an image
- Sum a list of numbers in Python
- Suppress Scientific Notation in Numpy When Creating Array From Nested List
- Sum-subset with a fixed subset size
- Super slow lag/delay on initial keyboard animation of UITextField

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.