Skip to content

Commit c0e104e

Browse files
committed
Added SparseTable
1 parent 88c532c commit c0e104e

File tree

1 file changed

+51
-22
lines changed
  • src/main/java/com/williamfiset/algorithms/datastructures/sparsetable

1 file changed

+51
-22
lines changed

src/main/java/com/williamfiset/algorithms/datastructures/sparsetable/SparseTable.java

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,6 @@ public enum Operation {
4343
return Math.abs(gcd);
4444
};
4545

46-
47-
// Supply an array of values and an associative binary function. The function
48-
// is usually min, max sum, gcd, etc... see pre-made ones below.
4946
public SparseTable(int[] v, Operation op) {
5047
this.op = op;
5148
init(v);
@@ -85,53 +82,85 @@ private void init(int[] v) {
8582
print(t);
8683
}
8784

85+
// Queries [l, r] for the operation set on this Sparse table.
8886
public int query(int l, int r) {
8987
if (op == Operation.MIN) {
90-
return minQuery(l, r);
88+
return query(l, r, minFn);
9189
} else if (op == Operation.MAX) {
92-
return maxQuery(l, r);
90+
return query(l, r, maxFn);
9391
}
92+
// TODO(william): add query for gcd
9493
return sumQuery(l, r);
9594
}
9695

97-
// Do sum query [l, r] in O(lg(n))
96+
// Do sum query [l, r] in O(lg(n)). Does a cascading query which shrinks the left endpoint
97+
// while summing over all the intervals which are powers of 2 between [l, r].
98+
// TODO(william): use longs?
9899
public int sumQuery(int l, int r) {
99100
int sum = 0;
100101
for (int p = P; p >= 0; p--) {
101-
// System.out.println(l + " " + r);
102102
int rangeLength = r - l + 1;
103103
if ((1 << p) <= rangeLength) {
104+
// System.out.printf("power = 2^%d = %d, l = %d, value = %d\n", p, 1<<p, l, t[p][l]);
104105
sum += t[p][l];
105106
l += (1 << p);
106107
}
107108
}
108109
return sum;
109110
}
110111

111-
// Do min query [l, r] in O(1)
112-
private int minQuery(int l, int r) {
112+
// Do either a min, max or gcd query on the interval [l, r] in O(1).
113+
//
114+
// We can get O(1) query by finding the smallest power of 2 that fits within the interval length
115+
// which we'll call k. Then we can query the intervals [l, l+k] and [r-k+1, r] (which likely
116+
// overlap) and apply the function again. Some functions (like min and max) don't care about
117+
// overlapping intervals so this trick works, but for a function like sum this would return the
118+
// wrong result.
119+
private int query(int l, int r, BinaryOperator<Integer> fn) {
120+
int len = r - l + 1;
113121
int p = log2[r - l + 1];
114-
return Math.min(t[p][l], t[p][r - (1 << p) + 1]);
122+
return fn.apply(t[p][l], t[p][r - (1 << p) + 1]);
115123
}
116124

117-
// Do max query [l, r] in O(1)
118-
private int maxQuery(int l, int r) {
119-
int p = log2[r - l + 1];
120-
return Math.max(t[p][l], t[p][r - (1 << p) + 1]);
121-
}
122-
123-
private void print(int[][] t) {
124-
for (int[] r : t) {
125-
System.out.println(java.util.Arrays.toString(r));
125+
private static void print(int[][] t) {
126+
for (int i = 0; i < t.length; i++) {
127+
for (int j = 0; j < t[0].length; j++) {
128+
System.out.printf("%3d,", t[i][j]);
129+
}
130+
System.out.println();
126131
}
127132
System.out.println();
128133
}
129134

130135
public static void main(String[] args) {
131-
int[] v = {1,8,5,6,7,2,7,1,8,5,6,7,2,4,3};
132-
System.out.println(v.length);
133-
SparseTable st = new SparseTable(v, Operation.MIN);
136+
int[] v = {1,2,3,4,5,6,7,8};
137+
SparseTable st = new SparseTable(v, Operation.SUM);
138+
System.out.println(st.query(1, 7));
139+
simpleTest();
140+
}
141+
142+
private static void simpleTest() {
143+
int[] v = {1,2,3,4,5,6,7,8};
144+
SparseTable st = new SparseTable(v, Operation.SUM);
145+
for (int i = 0; i < v.length; i++) {
146+
for (int j = i; j < v.length; j++) {
147+
int trueSum = 0;
148+
for (int k = i; k <= j; k++) {
149+
trueSum += v[k];
150+
}
151+
if (st.query(i, j) != trueSum) {
152+
System.out.printf("Ooopse, got %d instead of %d!\n", st.query(i, j), trueSum);
153+
}
154+
}
155+
}
134156
}
135157

136158
}
137159

160+
161+
162+
163+
164+
165+
166+

0 commit comments

Comments
 (0)