Skip to content

Commit d10cabd

Browse files
committed
ST work
1 parent 07e8427 commit d10cabd

File tree

3 files changed

+39
-22
lines changed

3 files changed

+39
-22
lines changed
Binary file not shown.

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

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public enum Operation {
3838
MIN,
3939
MAX,
4040
SUM,
41+
MULT,
4142
GCD
4243
};
4344

@@ -47,6 +48,7 @@ public enum Operation {
4748
private BinaryOperator<Long> sumFn = (a, b) -> a + b;
4849
private BinaryOperator<Long> minFn = (a, b) -> Math.min(a, b);
4950
private BinaryOperator<Long> maxFn = (a, b) -> Math.max(a, b);
51+
private BinaryOperator<Long> multFn = (a, b) -> a * b;
5052
private BinaryOperator<Long> gcdFn =
5153
(a, b) -> {
5254
long gcd = a;
@@ -106,6 +108,8 @@ private void init(long[] v) {
106108
}
107109
} else if (op == Operation.SUM) {
108110
dp[i][j] = sumFn.apply(leftInterval, rightInterval);
111+
} else if (op == Operation.MULT) {
112+
dp[i][j] = multFn.apply(leftInterval, rightInterval);
109113
} else if (op == Operation.GCD) {
110114
dp[i][j] = gcdFn.apply(leftInterval, rightInterval);
111115
}
@@ -126,14 +130,21 @@ private void printTable() {
126130

127131
// Queries [l, r] for the operation set on this sparse table.
128132
public long query(int l, int r) {
133+
// Fast queries types, O(1)
129134
if (op == Operation.MIN) {
130135
return query(l, r, minFn);
131136
} else if (op == Operation.MAX) {
132137
return query(l, r, maxFn);
133138
} else if (op == Operation.GCD) {
134139
return query(l, r, gcdFn);
135140
}
136-
return sumQuery(l, r);
141+
142+
// Slower query types, O(log2(n))
143+
if (op == Operation.SUM) {
144+
return sumQuery(l, r);
145+
} else {
146+
return multQuery(l, r);
147+
}
137148
}
138149

139150
public int queryIndex(int l, int r) {
@@ -148,7 +159,7 @@ public int queryIndex(int l, int r) {
148159

149160
private int minQueryIndex(int l, int r) {
150161
int len = r - l + 1;
151-
int p = log2[r - l + 1];
162+
int p = log2[len];
152163
long leftInterval = dp[p][l];
153164
long rightInterval = dp[p][r - (1 << p) + 1];
154165
if (leftInterval <= rightInterval) {
@@ -160,7 +171,7 @@ private int minQueryIndex(int l, int r) {
160171

161172
private int maxQueryIndex(int l, int r) {
162173
int len = r - l + 1;
163-
int p = log2[r - l + 1];
174+
int p = log2[len];
164175
long leftInterval = dp[p][l];
165176
long rightInterval = dp[p][r - (1 << p) + 1];
166177
if (leftInterval >= rightInterval) {
@@ -184,14 +195,25 @@ private long sumQuery(int l, int r) {
184195
for (int p = P; p >= 0; p--) {
185196
int rangeLength = r - l + 1;
186197
if ((1 << p) <= rangeLength) {
187-
// System.out.printf("[%d, %d)\n", l, l + (1<<p));
188198
sum += dp[p][l];
189199
l += (1 << p);
190200
}
191201
}
192202
return sum;
193203
}
194204

205+
private long multQuery(int l, int r) {
206+
long result = 1;
207+
for (int p = P; p >= 0; p--) {
208+
int rangeLength = r - l + 1;
209+
if ((1 << p) <= rangeLength) {
210+
result *= dp[p][l];
211+
l += (1 << p);
212+
}
213+
}
214+
return result;
215+
}
216+
195217
// Do either a min, max or gcd query on the interval [l, r] in O(1).
196218
//
197219
// We can get O(1) query by finding the smallest power of 2 that fits within the interval length
@@ -201,7 +223,7 @@ private long sumQuery(int l, int r) {
201223
// wrong result since it is not an idempotent binary function.
202224
private long query(int l, int r, BinaryOperator<Long> fn) {
203225
int len = r - l + 1;
204-
int p = log2[r - l + 1];
226+
int p = log2[len];
205227
return fn.apply(dp[p][l], dp[p][r - (1 << p) + 1]);
206228
}
207229

@@ -217,27 +239,16 @@ private static void example1() {
217239
// Initialize sparse table to do range minimum queries.
218240
SparseTable sparseTable = new SparseTable(values, SparseTable.Operation.MIN);
219241

220-
// Prints: "Min value between [2, 7] = -1"
221242
System.out.printf("Min value between [2, 7] = %d\n", sparseTable.query(2, 7));
222-
223-
// Prints: "Index of min value between [2, 7] = 5". Returns the leftmost index in the
224-
// event that there are duplicates.
225-
System.out.printf("Index of min value between [2, 7] = %d\n", sparseTable.queryIndex(2, 7));
226243
}
227244

228245
private static void example2() {
229246
long[] values = {4, 2, 3, 7, 1, 5, 3, 3, 9, 6, 7, -1, 4};
230-
System.out.println(values.length);
231247

232248
// Initialize sparse table to do range minimum queries.
233249
SparseTable sparseTable = new SparseTable(values, SparseTable.Operation.MIN);
234250

235-
// Prints: "Min value between [2, 7] = -1"
236251
System.out.printf("Min value between [2, 7] = %d\n", sparseTable.query(2, 7));
237-
238-
// Prints: "Index of min value between [2, 7] = 5". Returns the leftmost index in the
239-
// event that there are duplicates.
240-
// System.out.printf("Index of min value between [2, 7] = %d\n", sparseTable.queryIndex(2, 7));
241252
}
242253

243254
private static void example3() {
@@ -247,11 +258,6 @@ private static void example3() {
247258
// Initialize sparse table to do range minimum queries.
248259
SparseTable sparseTable = new SparseTable(values, SparseTable.Operation.SUM);
249260

250-
// Prints: "Min value between [2, 7] = -1"
251261
System.out.printf("Min value between [5, 17] = %d\n", sparseTable.query(5, 17));
252-
253-
// Prints: "Index of min value between [5, 17] = 5". Returns the leftmost index in the
254-
// event that there are duplicates.
255-
// System.out.printf("Index of min value between [5, 17] = %d\n", sparseTable.queryIndex(2, 7));
256262
}
257263
}

src/test/java/com/williamfiset/algorithms/datastructures/sparsetable/SparseTableTest.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ private void queryResultTest(
1515
maxQuery(values, l, r, actual, index);
1616
} else if (op == SparseTable.Operation.SUM) {
1717
sumQuery(values, l, r, actual);
18+
} else if (op == SparseTable.Operation.MULT) {
19+
multQuery(values, l, r, actual);
1820
} else if (op == SparseTable.Operation.GCD) {
1921
gcdQuery(values, l, r, actual);
20-
}
22+
}
2123
}
2224

2325
private void minQuery(long[] values, int l, int r, long actual, int index) {
@@ -40,6 +42,12 @@ private void sumQuery(long[] values, int l, int r, long actual) {
4042
assertThat(m).isEqualTo(actual);
4143
}
4244

45+
private void multQuery(long[] values, int l, int r, long actual) {
46+
long m = 1;
47+
for (int i = l; i <= r; i++) m *= values[i];
48+
assertThat(m).isEqualTo(actual);
49+
}
50+
4351
// Computes the Greatest Common Divisor (GCD) of a & b
4452
// This method ensures that the value returned is non negative
4553
public static long gcd(long a, long b) {
@@ -56,6 +64,7 @@ private void testAllOperations(long[] values) {
5664
SparseTable min_st = new SparseTable(values, SparseTable.Operation.MIN);
5765
SparseTable max_st = new SparseTable(values, SparseTable.Operation.MAX);
5866
SparseTable sum_st = new SparseTable(values, SparseTable.Operation.SUM);
67+
SparseTable mult_st = new SparseTable(values, SparseTable.Operation.MULT);
5968
SparseTable gcd_st = new SparseTable(values, SparseTable.Operation.GCD);
6069

6170
for (int i = 0; i < values.length; i++) {
@@ -66,6 +75,8 @@ private void testAllOperations(long[] values) {
6675
values, i, j, max_st.query(i, j), max_st.queryIndex(i, j), SparseTable.Operation.MAX);
6776
queryResultTest(
6877
values, i, j, sum_st.query(i, j), -1 /* unused */, SparseTable.Operation.SUM);
78+
queryResultTest(
79+
values, i, j, mult_st.query(i, j), -1 /* unused */, SparseTable.Operation.MULT);
6980
queryResultTest(
7081
values, i, j, gcd_st.query(i, j), -1 /* unused */, SparseTable.Operation.GCD);
7182
}

0 commit comments

Comments
 (0)