Sparse table
A sparse table answers range minimum, maximum and GCD queries in O(1) after O(n log n) preprocessing, by covering any range with two overlapping power-of-two blocks.
Learning goals
- Explain why the overlap of two blocks is harmless for min, max and GCD but not for sums
- Build the table level by level from the level below
- Precompute floor(log2) values or use Integer.numberOfLeadingZeros
- Answer range minimum queries in O(1), returning either the value or the index
Prerequisites
A segment tree answers a range minimum in O(log n). If the array never changes and there are millions of queries, paying O(n log n) once to make every query two table reads is a much better deal.
Idempotent operations
An operation is **idempotent** if applying it to the same value twice changes nothing: op(x, x) = x. Minimum, maximum, GCD, bitwise AND and OR are idempotent; sum, product and XOR are not. The sparse table's trick only works for idempotent operations, because it covers a range by two blocks that may overlap and so counts the overlapping values twice.
Open the animation's preset "Sum goes wrong (overlap)": the same two overlapping blocks give 46 instead of the true 26, because three positions are counted twice. For a minimum the same overlap is harmless, since min(x, x) = x. If your operation is not idempotent, use the disjoint sparse table of the next lesson.
| Operation | op(x, x) | Idempotent? | Sparse table works? |
|---|---|---|---|
| minimum / maximum | x | yes | yes |
| GCD | x | yes | yes |
| AND / OR | x | yes | yes |
| sum | 2x | no | no (double counts) |
| XOR | 0 | no | no (cancels) |
| product | x² | no | no |
1static long sumByTwoBlocks(int[] a, int l, int r) { // WRONG for sums: shows what the overlap does2int k = 31 - Integer.numberOfLeadingZeros(r - l + 1);3long left = 0, right = 0;4for (int i = l; i < l + (1 << k); i++) left += a[i];5for (int i = r - (1 << k) + 1; i <= r; i++) right += a[i];6return left + right; // counts the positions in both blocks twice7}
Sparse table: O(1) range queries from two overlapping blocks
Interactive · edit the inputlevel 0: min of 1 value starting at i
Level 0 is the array itself. Level k holds the min of every block of 2^k consecutive values, and only 4 levels are needed because 2^3 ≤ 8.
1int[][] st; // st[k][i] = op over a[i .. i + 2^k - 1]2void build(int[] a) {3int n = a.length, K = 32 - Integer.numberOfLeadingZeros(n);4st = new int[K][n];5st[0] = a.clone();6for (int k = 1; k < K; k++)7for (int i = 0; i + (1 << k) <= n; i++)8st[k][i] = Math.min(st[k - 1][i], st[k - 1][i + (1 << (k - 1))]); // two halves of the block9}10int query(int l, int r) { // inclusive11int k = 31 - Integer.numberOfLeadingZeros(r - l + 1); // floor(log2(length))12return Math.min(st[k][l], st[k][r - (1 << k) + 1]); // two blocks that may overlap13}
Live state
n
8
levels
4
Execution trace (dry run table)Show 7 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L5 | n=8 levels=4 | Level 0 is the array itself. Level k holds the min of every block of 2^k consecutive values, and only 4 levels are needed because 2^3 ≤ 8. |
| 2 | L8 | k=1 block length=2 cells=7 | Level 1: each cell combines two adjacent cells of level 0, st[1][i] = min(st[0][i], st[0][i + 1]). 7 cells computed. |
| 3 | L8 | k=2 block length=4 cells=5 | Level 2: each cell combines two adjacent cells of level 1, st[2][i] = min(st[1][i], st[1][i + 2]). 5 cells computed. |
| 4 | L8 | k=3 block length=8 cells=1 | Level 3: each cell combines two adjacent cells of level 2, st[3][i] = min(st[2][i], st[2][i + 4]). 1 cell computed. |
| 5 | L11 | l=1 r=5 length=5 k=2 | Query [1, 5]: length 5, so k = floor(log2 5) = 2. Two blocks of 4 values cover the range: one starting at l = 1, one ending at r = 5. |
| 6 | L12 | st[k][l]=2 st[k][r-2^k+1]=3 min=2 overlap=3 | Left block [1, 4] gives 2, right block [2, 5] gives 3. They overlap on 3 positions. |
| 7 | L12 | return=2 | min(a[1..5]) = 2, from two table reads: O(1) per query after an O(n log n) build. Counting a position twice cannot change a min. |
Min/max/GCD
The table has one row per level. Level k stores, for every start i with i + 2^k <= n, the answer for the block of 2^k values starting at i. Level 0 is the array. Each cell of level k combines two adjacent cells of level k - 1: st[k][i] = op(st[k-1][i], st[k-1][i + 2^(k-1)]). Passing the operation as a parameter gives one class for min, max, GCD, AND and OR.
The build costs O(n log n) time and space: about n cells per level and ⌊log2 n⌋ + 1 levels. In the preset "Range GCD" (12 18 8 24 36 9 6 30) the animation builds 4 levels, and the query over positions 0 to 4 returns 2 from two blocks of length 4.
1class SparseTable {2private final int[][] st;3private final IntBinaryOperator op; // must be associative and idempotent4SparseTable(int[] a, IntBinaryOperator op) {5this.op = op;6int n = a.length, K = 32 - Integer.numberOfLeadingZeros(n);7st = new int[K][];8st[0] = a.clone();9for (int k = 1; k < K; k++) {10st[k] = new int[n - (1 << k) + 1];11for (int i = 0; i + (1 << k) <= n; i++)12st[k][i] = op.applyAsInt(st[k - 1][i], st[k - 1][i + (1 << (k - 1))]); // two halves of the block13}14}15int query(int l, int r) { // inclusive, 0-based16int k = 31 - Integer.numberOfLeadingZeros(r - l + 1);17return op.applyAsInt(st[k][l], st[k][r - (1 << k) + 1]);18}19}
Sparse table: O(1) range queries from two overlapping blocks
Interactive · edit the inputlevel 0: min of 1 value starting at i
Level 0 is the array itself. Level k holds the min of every block of 2^k consecutive values, and only 4 levels are needed because 2^3 ≤ 8.
1int[][] st; // st[k][i] = op over a[i .. i + 2^k - 1]2void build(int[] a) {3int n = a.length, K = 32 - Integer.numberOfLeadingZeros(n);4st = new int[K][n];5st[0] = a.clone();6for (int k = 1; k < K; k++)7for (int i = 0; i + (1 << k) <= n; i++)8st[k][i] = Math.min(st[k - 1][i], st[k - 1][i + (1 << (k - 1))]); // two halves of the block9}10int query(int l, int r) { // inclusive11int k = 31 - Integer.numberOfLeadingZeros(r - l + 1); // floor(log2(length))12return Math.min(st[k][l], st[k][r - (1 << k) + 1]); // two blocks that may overlap13}
Live state
n
8
levels
4
Execution trace (dry run table)Show 7 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L5 | n=8 levels=4 | Level 0 is the array itself. Level k holds the min of every block of 2^k consecutive values, and only 4 levels are needed because 2^3 ≤ 8. |
| 2 | L8 | k=1 block length=2 cells=7 | Level 1: each cell combines two adjacent cells of level 0, st[1][i] = min(st[0][i], st[0][i + 1]). 7 cells computed. |
| 3 | L8 | k=2 block length=4 cells=5 | Level 2: each cell combines two adjacent cells of level 1, st[2][i] = min(st[1][i], st[1][i + 2]). 5 cells computed. |
| 4 | L8 | k=3 block length=8 cells=1 | Level 3: each cell combines two adjacent cells of level 2, st[3][i] = min(st[2][i], st[2][i + 4]). 1 cell computed. |
| 5 | L11 | l=1 r=5 length=5 k=2 | Query [1, 5]: length 5, so k = floor(log2 5) = 2. Two blocks of 4 values cover the range: one starting at l = 1, one ending at r = 5. |
| 6 | L12 | st[k][l]=2 st[k][r-2^k+1]=3 min=2 overlap=3 | Left block [1, 4] gives 2, right block [2, 5] gives 3. They overlap on 3 positions. |
| 7 | L12 | return=2 | min(a[1..5]) = 2, from two table reads: O(1) per query after an O(n log n) build. Counting a position twice cannot change a min. |
Precompute powers of two
A query needs k = floor(log2(length)). In Java the cheapest way is 31 - Integer.numberOfLeadingZeros(length), a single CPU instruction. A lookup table is the classic alternative that works in any language: lg[1] = 0 and lg[i] = lg[i / 2] + 1, computed once in O(n). Both give the same values, so use the built-in unless a table is clearer in your context.
The number of levels is floor(log2 n) + 1, which is 32 - Integer.numberOfLeadingZeros(n). For n = 8 that is 4 levels (blocks of 1, 2, 4 and 8); for n = 1 it is 1. Memory is the real limit of the structure: 10^6 values need 20 levels of up to 10^6 ints, about 80 MB.
| n | 1 | 2 | 3 | 4 | 7 | 8 | 1000 | 1,000,000 |
|---|---|---|---|---|---|---|---|---|
| levels = ⌊log2 n⌋ + 1 | 1 | 2 | 2 | 3 | 3 | 4 | 10 | 20 |
1static int[] logTable(int n) { // lg[i] = floor(log2 i) for i in 1..n2int[] lg = new int[n + 1];3for (int i = 2; i <= n; i++) lg[i] = lg[i / 2] + 1;4return lg;5}6static int levels(int n) { return 32 - Integer.numberOfLeadingZeros(n); }
Sparse table: O(1) range queries from two overlapping blocks
Interactive · edit the inputlevel 0: min of 1 value starting at i
Level 0 is the array itself. Level k holds the min of every block of 2^k consecutive values, and only 4 levels are needed because 2^3 ≤ 8.
1int[][] st; // st[k][i] = op over a[i .. i + 2^k - 1]2void build(int[] a) {3int n = a.length, K = 32 - Integer.numberOfLeadingZeros(n);4st = new int[K][n];5st[0] = a.clone();6for (int k = 1; k < K; k++)7for (int i = 0; i + (1 << k) <= n; i++)8st[k][i] = Math.min(st[k - 1][i], st[k - 1][i + (1 << (k - 1))]); // two halves of the block9}10int query(int l, int r) { // inclusive11int k = 31 - Integer.numberOfLeadingZeros(r - l + 1); // floor(log2(length))12return Math.min(st[k][l], st[k][r - (1 << k) + 1]); // two blocks that may overlap13}
Live state
n
8
levels
4
Execution trace (dry run table)Show 7 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L5 | n=8 levels=4 | Level 0 is the array itself. Level k holds the min of every block of 2^k consecutive values, and only 4 levels are needed because 2^3 ≤ 8. |
| 2 | L8 | k=1 block length=2 cells=7 | Level 1: each cell combines two adjacent cells of level 0, st[1][i] = min(st[0][i], st[0][i + 1]). 7 cells computed. |
| 3 | L8 | k=2 block length=4 cells=5 | Level 2: each cell combines two adjacent cells of level 1, st[2][i] = min(st[1][i], st[1][i + 2]). 5 cells computed. |
| 4 | L8 | k=3 block length=8 cells=1 | Level 3: each cell combines two adjacent cells of level 2, st[3][i] = min(st[2][i], st[2][i + 4]). 1 cell computed. |
| 5 | L11 | l=1 r=5 length=5 k=2 | Query [1, 5]: length 5, so k = floor(log2 5) = 2. Two blocks of 4 values cover the range: one starting at l = 1, one ending at r = 5. |
| 6 | L12 | st[k][l]=2 st[k][r-2^k+1]=3 min=2 overlap=3 | Left block [1, 4] gives 2, right block [2, 5] gives 3. They overlap on 3 positions. |
| 7 | L12 | return=2 | min(a[1..5]) = 2, from two table reads: O(1) per query after an O(n log n) build. Counting a position twice cannot change a min. |
O(1) RMQ
A **range minimum query** (RMQ) asks for the minimum of a[l..r]. With the sparse table it takes two reads and one comparison: let k = floor(log2(r - l + 1)) and return min(st[k][l], st[k][r - 2^k + 1]). The two blocks both lie inside [l, r] and together cover it, because each has length at least half of the range.
Often you need the position of the minimum, not only its value. Store indices instead of values and compare through the array; with <= for the left block the leftmost minimum wins. The preset "Range minimum" in the animation answers [1, 5] of 5 2 8 3 9 4 7 6 with 2, using blocks of length 4 starting at 1 and ending at 5.
1class RangeMin {2private final int[] a;3private final int[][] idx; // idx[k][i]: index of the minimum of a[i .. i + 2^k - 1]4RangeMin(int[] values) {5a = values.clone();6int n = a.length, K = 32 - Integer.numberOfLeadingZeros(n);7idx = new int[K][];8idx[0] = new int[n];9for (int i = 0; i < n; i++) idx[0][i] = i;10for (int k = 1; k < K; k++) {11idx[k] = new int[n - (1 << k) + 1];12for (int i = 0; i + (1 << k) <= n; i++) {13int x = idx[k - 1][i], y = idx[k - 1][i + (1 << (k - 1))];14idx[k][i] = a[x] <= a[y] ? x : y; // ties keep the left index15}16}17}18int argMin(int l, int r) {19int k = 31 - Integer.numberOfLeadingZeros(r - l + 1);20int x = idx[k][l], y = idx[k][r - (1 << k) + 1];21return a[x] <= a[y] ? x : y;22}23int min(int l, int r) { return a[argMin(l, r)]; }24}
Sparse table: O(1) range queries from two overlapping blocks
Interactive · edit the inputlevel 0: min of 1 value starting at i
Level 0 is the array itself. Level k holds the min of every block of 2^k consecutive values, and only 4 levels are needed because 2^3 ≤ 8.
1int[][] st; // st[k][i] = op over a[i .. i + 2^k - 1]2void build(int[] a) {3int n = a.length, K = 32 - Integer.numberOfLeadingZeros(n);4st = new int[K][n];5st[0] = a.clone();6for (int k = 1; k < K; k++)7for (int i = 0; i + (1 << k) <= n; i++)8st[k][i] = Math.min(st[k - 1][i], st[k - 1][i + (1 << (k - 1))]); // two halves of the block9}10int query(int l, int r) { // inclusive11int k = 31 - Integer.numberOfLeadingZeros(r - l + 1); // floor(log2(length))12return Math.min(st[k][l], st[k][r - (1 << k) + 1]); // two blocks that may overlap13}
Live state
n
8
levels
4
Execution trace (dry run table)Show 7 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L5 | n=8 levels=4 | Level 0 is the array itself. Level k holds the min of every block of 2^k consecutive values, and only 4 levels are needed because 2^3 ≤ 8. |
| 2 | L8 | k=1 block length=2 cells=7 | Level 1: each cell combines two adjacent cells of level 0, st[1][i] = min(st[0][i], st[0][i + 1]). 7 cells computed. |
| 3 | L8 | k=2 block length=4 cells=5 | Level 2: each cell combines two adjacent cells of level 1, st[2][i] = min(st[1][i], st[1][i + 2]). 5 cells computed. |
| 4 | L8 | k=3 block length=8 cells=1 | Level 3: each cell combines two adjacent cells of level 2, st[3][i] = min(st[2][i], st[2][i + 4]). 1 cell computed. |
| 5 | L11 | l=1 r=5 length=5 k=2 | Query [1, 5]: length 5, so k = floor(log2 5) = 2. Two blocks of 4 values cover the range: one starting at l = 1, one ending at r = 5. |
| 6 | L12 | st[k][l]=2 st[k][r-2^k+1]=3 min=2 overlap=3 | Left block [1, 4] gives 2, right block [2, 5] gives 3. They overlap on 3 positions. |
| 7 | L12 | return=2 | min(a[1..5]) = 2, from two table reads: O(1) per query after an O(n log n) build. Counting a position twice cannot change a min. |
Overlapping blocks
Why two blocks are enough: the longest power of two not above the length, 2^k, satisfies 2^k <= length < 2^(k+1). A block of 2^k starting at l and another ending at r together cover [l, r], because their total length 2 × 2^k is at least length. They overlap in 2^(k+1) - length positions, at least one, and exactly 2^k when the length is a power of two (then both are the same block).
For a non-idempotent operation you can still use a sparse table, but only with the binary decomposition of the length: take the largest block at l, move l forward by its size, and repeat. That costs O(log n) per query instead of O(1), the same as a Fenwick tree, so it is rarely worth the memory.
1static long[][] buildSums(int[] a) { // st[k][i] = sum of a[i .. i + 2^k - 1]2int n = a.length, K = 32 - Integer.numberOfLeadingZeros(n);3long[][] st = new long[K][];4st[0] = new long[n];5for (int i = 0; i < n; i++) st[0][i] = a[i];6for (int k = 1; k < K; k++) {7st[k] = new long[n - (1 << k) + 1];8for (int i = 0; i + (1 << k) <= n; i++) st[k][i] = st[k - 1][i] + st[k - 1][i + (1 << (k - 1))];9}10return st;11}12static long sumByDecomposition(long[][] st, int l, int r) { // O(log n): disjoint blocks, one per set bit of the length13long total = 0;14for (int k = st.length - 1; k >= 0; k--) {15if ((1 << k) <= r - l + 1) { total += st[k][l]; l += 1 << k; }16}17return total;18}
Sparse table: O(1) range queries from two overlapping blocks
Interactive · edit the inputlevel 0: min of 1 value starting at i
Level 0 is the array itself. Level k holds the min of every block of 2^k consecutive values, and only 4 levels are needed because 2^3 ≤ 8.
1int[][] st; // st[k][i] = op over a[i .. i + 2^k - 1]2void build(int[] a) {3int n = a.length, K = 32 - Integer.numberOfLeadingZeros(n);4st = new int[K][n];5st[0] = a.clone();6for (int k = 1; k < K; k++)7for (int i = 0; i + (1 << k) <= n; i++)8st[k][i] = Math.min(st[k - 1][i], st[k - 1][i + (1 << (k - 1))]); // two halves of the block9}10int query(int l, int r) { // inclusive11int k = 31 - Integer.numberOfLeadingZeros(r - l + 1); // floor(log2(length))12return Math.min(st[k][l], st[k][r - (1 << k) + 1]); // two blocks that may overlap13}
Live state
n
8
levels
4
Execution trace (dry run table)Show 7 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L5 | n=8 levels=4 | Level 0 is the array itself. Level k holds the min of every block of 2^k consecutive values, and only 4 levels are needed because 2^3 ≤ 8. |
| 2 | L8 | k=1 block length=2 cells=7 | Level 1: each cell combines two adjacent cells of level 0, st[1][i] = min(st[0][i], st[0][i + 1]). 7 cells computed. |
| 3 | L8 | k=2 block length=4 cells=5 | Level 2: each cell combines two adjacent cells of level 1, st[2][i] = min(st[1][i], st[1][i + 2]). 5 cells computed. |
| 4 | L8 | k=3 block length=8 cells=1 | Level 3: each cell combines two adjacent cells of level 2, st[3][i] = min(st[2][i], st[2][i + 4]). 1 cell computed. |
| 5 | L11 | l=1 r=5 length=5 k=2 | Query [1, 5]: length 5, so k = floor(log2 5) = 2. Two blocks of 4 values cover the range: one starting at l = 1, one ending at r = 5. |
| 6 | L12 | st[k][l]=2 st[k][r-2^k+1]=3 min=2 overlap=3 | Left block [1, 4] gives 2, right block [2, 5] gives 3. They overlap on 3 positions. |
| 7 | L12 | return=2 | min(a[1..5]) = 2, from two table reads: O(1) per query after an O(n log n) build. Counting a position twice cannot change a min. |
Practice ladder
Now try it yourself
Easy
- Range Sum Query - Immutable
Medium
- Sliding Window Maximum
- Longest Continuous Subarray With Absolute Diff Less Than or Equal to Limit
Advanced
- Static Range Minimum Queries (CSES)
- Static RMQ (Library Checker)
Key takeaways
- Level k holds the answer for every block of 2^k values; each cell combines two cells of the level below.
- Two overlapping blocks cover any range, so a query is two reads: O(1), but only for idempotent operations.
- Preprocessing costs O(n log n) time and memory; use it for static arrays with many queries.